File: [local] / sys / dev / hotplug.c (download)
Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:09:38 2008 UTC (16 years, 4 months ago) by nbrk
Branch: OPENBSD_4_2_BASE, MAIN
CVS Tags: jornada-partial-support-wip, HEAD Changes since 1.1: +0 -0 lines
Import of OpenBSD 4.2 release kernel tree with initial code to support
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO
Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)
|
/* $OpenBSD: hotplug.c,v 1.8 2006/05/28 16:43:49 mk 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/conf.h>
#include <sys/device.h>
#include <sys/fcntl.h>
#include <sys/hotplug.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/vnode.h>
#define HOTPLUG_MAXEVENTS 16
static int opened;
static struct hotplug_event evqueue[HOTPLUG_MAXEVENTS];
static int evqueue_head, evqueue_tail, evqueue_count;
static struct selinfo hotplug_sel;
void filt_hotplugrdetach(struct knote *);
int filt_hotplugread(struct knote *, long);
struct filterops hotplugread_filtops =
{ 1, NULL, filt_hotplugrdetach, filt_hotplugread};
#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;
}
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)
{
if (evqueue_count == HOTPLUG_MAXEVENTS && opened) {
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++;
wakeup(&evqueue);
selwakeup(&hotplug_sel);
KNOTE(&hotplug_sel.si_note, 0);
return (0);
}
int
hotplug_get_event(struct hotplug_event *he)
{
int s;
if (evqueue_count == 0)
return (1);
s = splbio();
*he = evqueue[evqueue_tail];
evqueue_tail = EVQUEUE_NEXT(evqueue_tail);
evqueue_count--;
splx(s);
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;
while (hotplug_get_event(&he) == 0)
;
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);
again:
if (hotplug_get_event(&he) == 0)
return (uiomove(&he, sizeof(he), uio));
if (flags & IO_NDELAY)
return (EAGAIN);
error = tsleep(evqueue, PRIBIO | PCATCH, "htplev", 0);
if (error)
return (error);
goto again;
}
int
hotplugioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
switch (cmd) {
case FIOASYNC:
/* ignore */
case FIONBIO:
/* handled in the upper fs layer */
break;
default:
return (ENOTTY);
}
return (0);
}
int
hotplugpoll(dev_t dev, int events, struct proc *p)
{
int revents = 0;
if (events & (POLLIN | POLLRDNORM)) {
if (evqueue_count > 0)
revents |= events & (POLLIN | POLLRDNORM);
else
selrecord(p, &hotplug_sel);
}
return (revents);
}
int
hotplugkqfilter(dev_t dev, struct knote *kn)
{
struct klist *klist;
int s;
switch (kn->kn_filter) {
case EVFILT_READ:
klist = &hotplug_sel.si_note;
kn->kn_fop = &hotplugread_filtops;
break;
default:
return (1);
}
s = splbio();
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
splx(s);
return (0);
}
void
filt_hotplugrdetach(struct knote *kn)
{
int s;
s = splbio();
SLIST_REMOVE(&hotplug_sel.si_note, kn, knote, kn_selnext);
splx(s);
}
int
filt_hotplugread(struct knote *kn, long hint)
{
kn->kn_data = evqueue_count;
return (evqueue_count > 0);
}