root/dev/hotplug.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hotplugattach
  2. hotplug_device_attach
  3. hotplug_device_detach
  4. hotplug_put_event
  5. hotplug_get_event
  6. hotplugopen
  7. hotplugclose
  8. hotplugread
  9. hotplugioctl
  10. hotplugpoll
  11. hotplugkqfilter
  12. filt_hotplugrdetach
  13. filt_hotplugread

    1 /*      $OpenBSD: hotplug.c,v 1.8 2006/05/28 16:43:49 mk Exp $  */
    2 /*
    3  * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
    4  *
    5  * Permission to use, copy, modify, and distribute this software for any
    6  * purpose with or without fee is hereby granted, provided that the above
    7  * copyright notice and this permission notice appear in all copies.
    8  *
    9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16  */
   17 
   18 /*
   19  * Device attachment and detachment notifications.
   20  */
   21 
   22 #include <sys/param.h>
   23 #include <sys/systm.h>
   24 #include <sys/conf.h>
   25 #include <sys/device.h>
   26 #include <sys/fcntl.h>
   27 #include <sys/hotplug.h>
   28 #include <sys/ioctl.h>
   29 #include <sys/poll.h>
   30 #include <sys/vnode.h>
   31 
   32 #define HOTPLUG_MAXEVENTS       16
   33 
   34 static int opened;
   35 static struct hotplug_event evqueue[HOTPLUG_MAXEVENTS];
   36 static int evqueue_head, evqueue_tail, evqueue_count;
   37 static struct selinfo hotplug_sel;
   38 
   39 void filt_hotplugrdetach(struct knote *);
   40 int  filt_hotplugread(struct knote *, long);
   41 
   42 struct filterops hotplugread_filtops =
   43         { 1, NULL, filt_hotplugrdetach, filt_hotplugread};
   44 
   45 #define EVQUEUE_NEXT(p) (p == HOTPLUG_MAXEVENTS - 1 ? 0 : p + 1)
   46 
   47 
   48 int hotplug_put_event(struct hotplug_event *);
   49 int hotplug_get_event(struct hotplug_event *);
   50 
   51 void hotplugattach(int);
   52 
   53 void
   54 hotplugattach(int count)
   55 {
   56         opened = 0;
   57         evqueue_head = 0;
   58         evqueue_tail = 0;
   59         evqueue_count = 0;
   60 }
   61 
   62 void
   63 hotplug_device_attach(enum devclass class, char *name)
   64 {
   65         struct hotplug_event he;
   66 
   67         he.he_type = HOTPLUG_DEVAT;
   68         he.he_devclass = class;
   69         strlcpy(he.he_devname, name, sizeof(he.he_devname));
   70         hotplug_put_event(&he);
   71 }
   72 
   73 void
   74 hotplug_device_detach(enum devclass class, char *name)
   75 {
   76         struct hotplug_event he;
   77 
   78         he.he_type = HOTPLUG_DEVDT;
   79         he.he_devclass = class;
   80         strlcpy(he.he_devname, name, sizeof(he.he_devname));
   81         hotplug_put_event(&he);
   82 }
   83 
   84 int
   85 hotplug_put_event(struct hotplug_event *he)
   86 {
   87         if (evqueue_count == HOTPLUG_MAXEVENTS && opened) {
   88                 printf("hotplug: event lost, queue full\n");
   89                 return (1);
   90         }
   91 
   92         evqueue[evqueue_head] = *he;
   93         evqueue_head = EVQUEUE_NEXT(evqueue_head);
   94         if (evqueue_count == HOTPLUG_MAXEVENTS)
   95                 evqueue_tail = EVQUEUE_NEXT(evqueue_tail);
   96         else 
   97                 evqueue_count++;
   98         wakeup(&evqueue);
   99         selwakeup(&hotplug_sel);
  100         KNOTE(&hotplug_sel.si_note, 0);
  101         return (0);
  102 }
  103 
  104 int
  105 hotplug_get_event(struct hotplug_event *he)
  106 {
  107         int s;
  108 
  109         if (evqueue_count == 0)
  110                 return (1);
  111 
  112         s = splbio();
  113         *he = evqueue[evqueue_tail];
  114         evqueue_tail = EVQUEUE_NEXT(evqueue_tail);
  115         evqueue_count--;
  116         splx(s);
  117         return (0);
  118 }
  119 
  120 int
  121 hotplugopen(dev_t dev, int flag, int mode, struct proc *p)
  122 {
  123         if (minor(dev) != 0)
  124                 return (ENXIO);
  125         if ((flag & FWRITE))
  126                 return (EPERM);
  127         if (opened)
  128                 return (EBUSY);
  129         opened = 1;
  130         return (0);
  131 }
  132 
  133 int
  134 hotplugclose(dev_t dev, int flag, int mode, struct proc *p)
  135 {
  136         struct hotplug_event he;
  137 
  138         while (hotplug_get_event(&he) == 0)
  139                 ;
  140         opened = 0;
  141         return (0);
  142 }
  143 
  144 int
  145 hotplugread(dev_t dev, struct uio *uio, int flags)
  146 {
  147         struct hotplug_event he;
  148         int error;
  149 
  150         if (uio->uio_resid != sizeof(he))
  151                 return (EINVAL);
  152 
  153 again:
  154         if (hotplug_get_event(&he) == 0)
  155                 return (uiomove(&he, sizeof(he), uio));
  156         if (flags & IO_NDELAY)
  157                 return (EAGAIN);
  158 
  159         error = tsleep(evqueue, PRIBIO | PCATCH, "htplev", 0);
  160         if (error)
  161                 return (error);
  162         goto again;
  163 }
  164 
  165 int
  166 hotplugioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
  167 {
  168         switch (cmd) {
  169         case FIOASYNC:
  170                 /* ignore */
  171         case FIONBIO:
  172                 /* handled in the upper fs layer */
  173                 break;
  174         default:
  175                 return (ENOTTY);
  176         }
  177 
  178         return (0);
  179 }
  180 
  181 int
  182 hotplugpoll(dev_t dev, int events, struct proc *p)
  183 {
  184         int revents = 0;
  185 
  186         if (events & (POLLIN | POLLRDNORM)) {
  187                 if (evqueue_count > 0)
  188                         revents |= events & (POLLIN | POLLRDNORM);
  189                 else
  190                         selrecord(p, &hotplug_sel);
  191         }
  192 
  193         return (revents);
  194 }
  195 
  196 int
  197 hotplugkqfilter(dev_t dev, struct knote *kn)
  198 {
  199         struct klist *klist;
  200         int s;
  201 
  202         switch (kn->kn_filter) {
  203         case EVFILT_READ:
  204                 klist = &hotplug_sel.si_note;
  205                 kn->kn_fop = &hotplugread_filtops;
  206                 break;
  207         default:
  208                 return (1);
  209         }
  210 
  211         s = splbio();
  212         SLIST_INSERT_HEAD(klist, kn, kn_selnext);
  213         splx(s);
  214         return (0);
  215 }
  216 
  217 void
  218 filt_hotplugrdetach(struct knote *kn)
  219 {
  220         int s;
  221 
  222         s = splbio();
  223         SLIST_REMOVE(&hotplug_sel.si_note, kn, knote, kn_selnext);
  224         splx(s);
  225 }
  226 
  227 int
  228 filt_hotplugread(struct knote *kn, long hint)
  229 {
  230         kn->kn_data = evqueue_count;
  231 
  232         return (evqueue_count > 0);
  233 }

/* [<][>][^][v][top][bottom][index][help] */