Added Device Manager (USB hotplug support)

This commit is contained in:
Dirk Vogt 2011-02-23 13:48:03 +00:00
parent bac0222eec
commit 00dcbb9dc6
12 changed files with 1170 additions and 2 deletions

View file

@ -23,6 +23,7 @@
* 0xF00 - 0xFFF Scheduling messages
* 0x1000 - 0x10FF Notify messages
* 0x1100 - 0x11FF USB
* 0x1200 - 0x12FF Devman
* 0x1300 - 0x13FF TTY Input
*
* Zero and negative values are widely used for OK and error responses.
@ -1203,6 +1204,32 @@
# define USB_INTERFACES m4_l3
# define USB_RB_INIT_NAME m3_ca1
/*===========================================================================*
* Messages for DeviceManager (s/t like SysFS) *
*===========================================================================*/
#define DEVMAN_BASE 0x1200
#define DEVMAN_ADD_DEV (DEVMAN_BASE + 0)
#define DEVMAN_DEL_DEV (DEVMAN_BASE + 1)
#define DEVMAN_ADD_BUS (DEVMAN_BASE + 2)
#define DEVMAN_DEL_BUS (DEVMAN_BASE + 3)
#define DEVMAN_ADD_DEVFILE (DEVMAN_BASE + 4)
#define DEVMAN_DEL_DEVFILE (DEVMAN_BASE + 5)
#define DEVMAN_REQUEST (DEVMAN_BASE + 6)
#define DEVMAN_REPLY (DEVMAN_BASE + 7)
#define DEVMAN_BIND (DEVMAN_BASE + 8)
#define DEVMAN_UNBIND (DEVMAN_BASE + 9)
# define DEVMAN_GRANT_ID m4_l1
# define DEVMAN_GRANT_SIZE m4_l2
# define DEVMAN_ENDPOINT m4_l3
# define DEVMAN_DEVICE_ID m4_l2
# define DEVMAN_RESULT m4_l1
/*===========================================================================*
* TTY INPUT INJECTION *
*===========================================================================*/

View file

@ -27,7 +27,7 @@ INCS+= minix/a.out.h minix/cdrom.h minix/cpufeature.h \
minix/vfsif.h minix/vtreefs.h \
minix/compiler-ack.h minix/sha2.h minix/sha1.h minix/md5.h \
minix/audio_fw.h minix/hash.h minix/input.h \
minix/usb.h minix/usb_ch9.h
minix/devman.h minix/usb.h minix/usb_ch9.h
INCS+= net/hton.h net/if.h net/ioctl.h net/netlib.h
INCS+= netinet/if_ether.h netinet/in.h netinet/tcp.h

72
include/minix/devman.h Normal file
View file

@ -0,0 +1,72 @@
#ifndef MINIX_LIBDEVMAN_H
#define MINIX_LIBDEVMAN_H
#include <minix/com.h>
#include <minix/ipc.h>
#include <minix/usb_ch9.h>
/* used for serializing */
struct devman_device_info {
int count;
int parent_dev_id;
unsigned name_offset;
unsigned subsystem_offset;
};
struct devman_device_info_entry {
unsigned type;
unsigned name_offset;
unsigned data_offset;
unsigned req_nr;
};
#ifndef DEVMAN_SERVER
struct devman_usb_bind_cb_data {
int dev_id;
int interface;
};
struct devman_usb_interface {
struct devman_dev *dev;
struct devman_usb_dev *usb_dev;
usb_interface_descriptor_t *desc;
/* used by the lib */
struct devman_usb_bind_cb_data cb_data;
};
struct devman_usb_dev {
struct devman_dev *dev;
int dev_id; /* The ID identifying the device
on server side */
usb_device_descriptor_t *desc;
int configuration; /* the configuration used for this
device */
char *manufacturer;
char *product;
char *serial;
int intf_count; /* the number of interfaces in the current
configuration */
struct devman_usb_interface interfaces[32];
/* used by the lib */
struct devman_usb_bind_cb_data cb_data;
};
typedef int (*devman_usb_bind_cb_t)(struct devman_usb_bind_cb_data *data, endpoint_t ep);
_PROTOTYPE( int devman_add_device, (struct devman_dev *dev));
_PROTOTYPE( int devman_del_device, (struct devman_dev *dev));
_PROTOTYPE( int devman_init, (void));
_PROTOTYPE( struct devman_usb_dev* devman_usb_device_new, (int dev_id));
_PROTOTYPE( int devman_usb_device_add, (struct devman_usb_dev *dev));
_PROTOTYPE( int devman_usb_device_remove, (struct devman_usb_dev *dev));
_PROTOTYPE( void devman_usb_device_delete, (struct devman_usb_dev *udev));
_PROTOTYPE( int devman_handle_msg, (message *m));
_PROTOTYPE( int devman_usb_init,(devman_usb_bind_cb_t bind_cb,
devman_usb_bind_cb_t unbind_cb));
#endif
#endif

View file

@ -4,7 +4,7 @@
.include <bsd.own.mk>
SUBDIR= ds ext2 hgfs inet init ipc is iso9660fs \
mfs pfs pm procfs rs sched vfs vm
mfs pfs pm procfs rs sched vfs vm devman
IMAGE_SUBDIR= ds init mfs pfs pm rs sched vfs vm

13
servers/devman/Makefile Normal file
View file

@ -0,0 +1,13 @@
PROG = devman
SRCS = main.c device.c buf.c bind.c
DPADD+= ${LIBSYS}
LDADD = -lvtreefs -lsys
BINDIR?= /sbin
INSTALLFLAGS+= -S 128k
MAN=
.include <bsd.prog.mk>
CFLAGS += -Wall

105
servers/devman/bind.c Normal file
View file

@ -0,0 +1,105 @@
#include "devman.h"
#include "proto.h"
/*****************************************************************************
* do_bind_device *
****************************************************************************/
PUBLIC int do_bind_device(message *m)
{
struct devman_device *dev;
int res;
endpoint_t src = m->m_source;
/* check if msg comes from RS */
if (src != RS_PROC_NR) {
m->DEVMAN_RESULT = EPERM;
printf("[W] could bind message from somebody else than RS\n");
return 0;
} else {
/* get the device */
dev = devman_find_device(m->DEVMAN_DEVICE_ID);
/* bind device at device provider*/
if (dev != NULL) {
m->m_type = DEVMAN_BIND;
/* ...device ID and endpoint is still set */
#ifdef DEBUG
printf("devman: bind call to %d for dev %d\n",
dev->owner, m->DEVMAN_DEVICE_ID);
#endif
res = sendrec(dev->owner, m);
if (res != OK) {
printf("[W] devman.do_bind_device(): could not send "
"message to device owner (%d)\n", res);
m->DEVMAN_RESULT= res;
} else if (m->DEVMAN_RESULT != OK) {
printf("[W] devman.do_bind_device(): driver could"
" not bind device (%d)\n", m->DEVMAN_RESULT);
} else {
dev->state = DEVMAN_DEVICE_BOUND;
devman_get_device(dev);
}
} else {
m->DEVMAN_RESULT = ENODEV;
}
m->m_type = DEVMAN_REPLY;
send(RS_PROC_NR, m);
}
return 0;
}
/*****************************************************************************
* do_unbind_device *
****************************************************************************/
PUBLIC int do_unbind_device(message *m)
{
struct devman_device *dev;
int res;
endpoint_t src = m->m_source;
/* check if msg comes from RS */
if (src != RS_PROC_NR) {
m->DEVMAN_RESULT = EPERM;
printf("[W] devman.do_unbind_device(): unbind message from somebody"
"else than RS (%d)\n", src);
return 0;
} else {
/* get the device */
dev = devman_find_device(m->DEVMAN_DEVICE_ID);
/* bind device at device provider*/
if (dev != NULL) {
m->m_type = DEVMAN_UNBIND;
/* ...device ID and endpoint is still set */
#ifdef DEBUG
printf("devman: unbind call to %d for dev %d\n",
dev->owner, m->DEVMAN_DEVICE_ID);
#endif
res = sendrec(dev->owner, m);
if (res != OK) {
printf("[W] devman.do_unbind_device(): could not send "
"message to device owner (%d)\n", res);
m->DEVMAN_RESULT= res;
} else if (m->DEVMAN_RESULT != OK && m->DEVMAN_RESULT != 19) {
/* device drive deleted device already? */
printf("[W] devman.do_unbind_device(): driver could"
" not unbind device (%d)\n", m->DEVMAN_RESULT);
} else {
if (dev->state != DEVMAN_DEVICE_ZOMBIE) {
dev->state = DEVMAN_DEVICE_UNBOUND;
}
devman_put_device(dev);
m->DEVMAN_RESULT = OK;
}
} else {
/* this might be the case, but perhaps its better to keep
the device in the db as long a driver is bound to it*/
m->DEVMAN_RESULT = ENODEV;
}
m->m_type = DEVMAN_REPLY;
send(RS_PROC_NR, m);
}
return 0;
}

167
servers/devman/buf.c Executable file
View file

@ -0,0 +1,167 @@
/* buf.c - by Alen Stojanov and David van Moolenbroek, taken from procfs */
#define _POSIX_SOURCE 1 /* tell headers to include POSIX stuff */
#define _MINIX 1 /* tell headers to include MINIX stuff */
#define _SYSTEM 1 /* tell headers that this is the kernel */
#define DEVMAN_SERVER 1
#include <minix/config.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <lib.h>
#include <timers.h>
#include <minix/callnr.h>
#include <minix/type.h>
#include <minix/const.h>
#include <minix/com.h>
#include <minix/syslib.h>
#include <minix/sysutil.h>
#include <minix/vfsif.h>
#include <minix/endpoint.h>
#include <minix/sysinfo.h>
#include <minix/u64.h>
#include <minix/sysinfo.h>
#include <minix/type.h>
#include <minix/ipc.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <minix/vtreefs.h>
#include <minix/devman.h>
#include <stdarg.h>
#include <assert.h>
#include <string.h>
#define BUF_SIZE 4096
PRIVATE char buf[BUF_SIZE + 1];
PRIVATE size_t off, left, used;
PRIVATE off_t skip;
#define MIN(x,y) (x<y?x:y)
/*===========================================================================*
* buf_init *
*===========================================================================*/
PUBLIC void buf_init(off_t start, size_t len)
{
/* Initialize the buffer for fresh use. The first 'start' bytes of the
* produced output are to be skipped. After that, up to a total of
* 'len' bytes are requested.
*/
skip = start;
left = MIN(len, BUF_SIZE);
off = 0;
used = 0;
}
/*===========================================================================*
* buf_printf *
*===========================================================================*/
PUBLIC void buf_printf(char *fmt, ...)
{
/* Add formatted text to the end of the buffer.
*/
va_list args;
ssize_t len, max;
if (left == 0)
return;
/* There is no way to estimate how much space the result will take, so
* we need to produce the string even when skipping part of the start.
* If part of the result is to be skipped, do not memcpy; instead, save
* the offset of where the result starts within the buffer.
*
* The null terminating character is not part of the result, so room
* must be given for it to be stored after completely filling up the
* requested part of the buffer.
*/
max = MIN(skip + left, BUF_SIZE);
va_start(args, fmt);
len = vsnprintf(&buf[off + used], max + 1, fmt, args);
va_end(args);
if (skip > 0) {
assert(off == 0);
assert(used == 0);
if (skip >= len) {
skip -= len;
return;
}
off = skip;
if (left > BUF_SIZE - off)
left = BUF_SIZE - off;
len -= off;
skip = 0;
}
assert(skip == 0);
assert(len >= 0);
assert((long) left >= 0);
if (len > (ssize_t) left)
len = left;
used += len;
left -= len;
}
/*===========================================================================*
* buf_append *
*===========================================================================*/
PUBLIC void buf_append(char *data, size_t len)
{
/* Add arbitrary data to the end of the buffer.
*/
if (left == 0)
return;
if (skip > 0) {
if (skip >= (ssize_t) len) {
skip -= len;
return;
}
data += skip;
len -= skip;
skip = 0;
}
if (len > left)
len = left;
memcpy(&buf[off + used], data, len);
used += len;
left -= len;
}
/*===========================================================================*
* buf_get *
*===========================================================================*/
PUBLIC size_t buf_get(char **ptr)
{
/* Return the buffer's starting address and the length of the used
* part, not counting the trailing null character for the latter.
*/
*ptr = &buf[off];
return used;
}

521
servers/devman/device.c Normal file
View file

@ -0,0 +1,521 @@
#include "devman.h"
#include "proto.h"
FORWARD _PROTOTYPE( struct devman_device*devman_dev_add_child,
(struct devman_device *parent,
struct devman_device_info *devinf) );
FORWARD _PROTOTYPE( struct devman_device *_find_dev,
(struct devman_device *dev, int dev_id) );
FORWARD _PROTOTYPE( int devman_dev_add_info,
(struct devman_device *dev,
struct devman_device_info_entry *entry,
char *buf) );
FORWARD _PROTOTYPE( int devman_event_read,
(char **ptr, size_t *len,off_t offset, void *data) );
FORWARD _PROTOTYPE( int devman_del_device, (struct devman_device *dev) );
PRIVATE int next_device_id = 1;
PRIVATE struct inode_stat default_dir_stat = {
/* .mode = */ S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH,
/* .uid = */ 0,
/* .gid = */ 0,
/* .size = */ 0,
/* .dev = */ NO_DEV,
};
PRIVATE struct inode_stat default_file_stat = {
/* .mode = */ S_IFREG | S_IRUSR | S_IRGRP | S_IROTH,
/* .uid = */ 0,
/* .gid = */ 0,
/* .size = */ 0x1000,
/* .dev = */ NO_DEV,
};
PRIVATE struct devman_device root_dev;
PRIVATE struct devman_event_inode event_inode_data = {
TAILQ_HEAD_INITIALIZER(event_inode_data.event_queue),
};
PRIVATE struct devman_inode event_inode;
/*===========================================================================*
* devman_generate_path *
*===========================================================================*/
PRIVATE int
devman_generate_path(char* buf, int len, struct devman_device *dev)
{
int res =0;
const char * name = ".";
const char * sep = "/";
if (dev != NULL) {
res = devman_generate_path(buf, len, dev->parent);
if (res != 0) {
return res;
}
name = get_inode_name(dev->inode.inode);
} else {
}
/* does it fit? */
if (strlen(buf) + strlen(name) + strlen(sep) + 1 > len) {
return ENOMEM;
}
strcat(buf, name);
strcat(buf, sep);
return 0;
}
/*===========================================================================*
* devman_device_add_event *
*===========================================================================*/
PRIVATE void
devman_device_add_event(struct devman_device* dev)
{
struct devman_event * event;
char buf[12]; /* this fits the device ID " 0xXXXXXXXX" */
int res;
event = malloc(sizeof(struct devman_event));
memset(event, 0, sizeof(event));
if (event == NULL) {
panic("devman_device_remove_event: out of memory\n");
}
strcat(event->data, ADD_STRING);
res = devman_generate_path(event->data, DEVMAN_STRING_LEN - 11 , dev);
if (res) {
panic("devman_device_add_event: "
"devman_generate_path failed: (%d)\n", res);
}
snprintf(buf, 12, " 0x%08x", dev->dev_id);
strcat(event->data,buf);
TAILQ_INSERT_HEAD(&event_inode_data.event_queue, event, events);
}
/*===========================================================================*
* devman_device_remove_event *
*===========================================================================*/
PRIVATE void
devman_device_remove_event(struct devman_device* dev)
{
struct devman_event * event;
char buf[12]; /* this fits the device ID " 0xXXXXXXXX" */
int res;
event = malloc(sizeof(struct devman_event));
memset(event, 0, sizeof(event));
if (event == NULL) {
panic("devman_device_remove_event: out of memory\n");
}
strcat(event->data, REMOVE_STRING);
res = devman_generate_path(event->data, DEVMAN_STRING_LEN-11, dev);
if (res) {
panic("devman_device_remove_event: "
"devman_generate_path failed: (%d)\n", res);
}
snprintf(buf, 12, " 0x%08x", dev->dev_id);
strcat(event->data,buf);
TAILQ_INSERT_HEAD(&event_inode_data.event_queue, event, events);
}
/*===========================================================================*
* devman_event_read *
*===========================================================================*/
PRIVATE int
devman_event_read(char **ptr, size_t *len,off_t offset, void *data)
{
struct devman_event *ev = NULL;
struct devman_event_inode *n;
static int eof = 0;
if (eof) {
*len=0;
eof = 0;
return 0;
}
n = (struct devman_event_inode *) data;
if (!TAILQ_EMPTY(&n->event_queue)) {
ev = TAILQ_LAST(&n->event_queue, event_head);
}
buf_init(offset, *len);
if (ev != NULL) {
buf_printf("%s", ev->data);
/* read all? */
if (*len + offset >= strlen(ev->data)) {
TAILQ_REMOVE(&n->event_queue, ev, events);
free(ev);
eof = 1;
}
}
*len = buf_get(ptr);
return 0;
}
/*===========================================================================*
* devman_static_info_read *
*===========================================================================*/
PRIVATE int
devman_static_info_read(char **ptr, size_t *len, off_t offset, void *data)
{
struct devman_static_info_inode *n;
n = (struct devman_static_info_inode *) data;
buf_init(offset, *len);
buf_printf("%s\n", n->data);
*len = buf_get(ptr);
return 0;
}
/*===========================================================================*
* devman_init_devices *
*===========================================================================*/
PUBLIC void devman_init_devices()
{
event_inode.data = &event_inode_data;
event_inode.read_fn = devman_event_read;
root_dev.dev_id = 0;
root_dev.major = -1;
root_dev.owner = 0;
root_dev.parent = NULL;
root_dev.inode.inode=
add_inode(get_root_inode(), "devices",
NO_INDEX, &default_dir_stat, 0, &root_dev.inode);
event_inode.inode=
add_inode(get_root_inode(), "events",
NO_INDEX, &default_file_stat, 0, &event_inode);
TAILQ_INIT(&root_dev.children);
TAILQ_INIT(&root_dev.infos);
}
/*===========================================================================*
* do_reply *
*===========================================================================*/
PRIVATE void do_reply(message *msg, int res)
{
msg->m_type = DEVMAN_REPLY;
msg->DEVMAN_RESULT = res;
send(msg->m_source, msg);
}
/*===========================================================================*
* do_add_device *
*===========================================================================*/
PUBLIC int do_add_device(message *msg)
{
endpoint_t ep = msg->m_source;
int res;
struct devman_device *dev;
struct devman_device *parent;
struct devman_device_info *devinf = NULL;
devinf = malloc(msg->DEVMAN_GRANT_SIZE);
if (devinf == NULL) {
res = ENOMEM;
do_reply(msg, res);
return 0;
}
res = sys_safecopyfrom(ep, msg->DEVMAN_GRANT_ID,
0, (vir_bytes) devinf, msg->DEVMAN_GRANT_SIZE, D);
if (res != OK) {
res = EINVAL;
free(devinf);
do_reply(msg, res);
return 0;
}
if ((parent = _find_dev(&root_dev, devinf->parent_dev_id))
== NULL) {
res = ENODEV;
free(devinf);
do_reply(msg, res);
return 0;
}
dev = devman_dev_add_child(parent, devinf);
dev->state = DEVMAN_DEVICE_UNBOUND;
if (dev == NULL) {
res = ENODEV;
free(devinf);
do_reply(msg, res);
return 0;
}
dev->owner = msg->m_source;
msg->DEVMAN_DEVICE_ID = dev->dev_id;
devman_device_add_event(dev);
do_reply(msg, res);
return 0;
}
/*===========================================================================*
* _find_dev *
*===========================================================================*/
PRIVATE struct devman_device *
_find_dev(struct devman_device *dev, int dev_id)
{
struct devman_device *_dev;
if(dev->dev_id == dev_id)
return dev;
TAILQ_FOREACH(_dev, &dev->children, siblings) {
struct devman_device *t = _find_dev(_dev, dev_id);
if (t !=NULL) {
return t;
}
}
return NULL;
}
/*===========================================================================*
* devman_find_dev *
*===========================================================================*/
PUBLIC struct devman_device *devman_find_device(int dev_id)
{
return _find_dev(&root_dev, dev_id);
}
/*===========================================================================*
* devman_dev_add_static_info *
*===========================================================================*/
PRIVATE int
devman_dev_add_static_info
(struct devman_device *dev, char * name, char *data)
{
struct devman_inode *inode;
struct devman_static_info_inode *st_inode;
st_inode = malloc(sizeof(struct devman_static_info_inode));
st_inode->dev = dev;
strncpy(st_inode->data, data, DEVMAN_STRING_LEN);
/* if string is longer it's truncated */
st_inode->data[DEVMAN_STRING_LEN-1] = 0;
inode = malloc (sizeof(struct devman_inode));
inode->data = st_inode;
inode->read_fn = devman_static_info_read;
inode->inode = add_inode(dev->inode.inode, name,
NO_INDEX, &default_file_stat, 0, inode);
/* add info to info_list */
TAILQ_INSERT_HEAD(&dev->infos, inode, inode_list);
return 0;
}
/*===========================================================================*
* devman_dev_add_child *
*===========================================================================*/
PRIVATE struct devman_device*
devman_dev_add_child
(struct devman_device *parent, struct devman_device_info *devinf)
{
int i;
char * buffer = (char *) (devinf);
char tmp_buf[128];
struct devman_device_info_entry *entries;
/* create device */
struct devman_device * dev = malloc(sizeof(struct devman_device));
if (parent == NULL) {
return NULL;
}
dev->ref_count = 1;
/* set dev_info */
dev->parent = parent;
dev->info = devinf;
dev->dev_id = next_device_id++;
dev->inode.inode =
add_inode(parent->inode.inode, buffer + devinf->name_offset,
NO_INDEX, &default_dir_stat, 0, &dev->inode);
TAILQ_INIT(&dev->children);
TAILQ_INIT(&dev->infos);
/* create information inodes */
entries = (struct devman_device_info_entry *)
(buffer + sizeof(struct devman_device_info));
for (i = 0; i < devinf->count ; i++) {
devman_dev_add_info(dev, &entries[i], buffer);
}
/* make device ID accessible to user land */
snprintf(tmp_buf, DEVMAN_STRING_LEN, "%d",dev->dev_id);
devman_dev_add_static_info(dev, "devman_id", tmp_buf);
TAILQ_INSERT_HEAD(&parent->children, dev, siblings);
devman_get_device(parent);
/* FUTURE TODO: create links(BUS, etc) */
return dev;
}
/*===========================================================================*
* devman_dev_add_info *
*===========================================================================*/
PRIVATE int
devman_dev_add_info
(struct devman_device *dev, struct devman_device_info_entry *entry, char *buf)
{
switch(entry->type) {
case DEVMAN_DEVINFO_STATIC:
return devman_dev_add_static_info(dev,
buf + entry->name_offset, buf + entry->data_offset);
case DEVMAN_DEVINFO_DYNAMIC:
/* TODO */
/* fall through */
default:
return -1;
}
}
/*===========================================================================*
* do_del_device *
*===========================================================================*/
PUBLIC int do_del_device(message *msg)
{
int dev_id = msg->DEVMAN_DEVICE_ID;
int res=0;
/* only parrent is allowed to add devices */
struct devman_device *dev = _find_dev(&root_dev, dev_id);
if (dev == NULL ) {
printf("devman: no dev with id %d\n",dev_id);
res = ENODEV;
}
#if 0
if (dev->parent->owner != ep) {
res = EPERM;
}
#endif
if (!res) {
devman_device_remove_event(dev);
if (dev->state == DEVMAN_DEVICE_BOUND) {
dev->state = DEVMAN_DEVICE_ZOMBIE;
}
devman_put_device(dev);
}
do_reply(msg, res);
return 0;
}
/*===========================================================================*
* devman_get_device *
*===========================================================================*/
PUBLIC void devman_get_device(struct devman_device *dev)
{
if (dev == NULL || dev == &root_dev) {
return;
}
dev->ref_count++;
}
/*===========================================================================*
* devman_put_device *
*===========================================================================*/
PUBLIC void devman_put_device(struct devman_device *dev)
{
if (dev == NULL || dev == &root_dev ) {
return;
}
dev->ref_count--;
if (dev->ref_count == 0) {
devman_del_device(dev);
}
}
/*===========================================================================*
* devman_del_device *
*===========================================================================*/
PRIVATE int devman_del_device(struct devman_device *dev)
{
/* does device have children -> error */
/* evtl. remove links */
/* free devinfo inodes */
struct devman_inode *inode, *_inode;
TAILQ_FOREACH_SAFE(inode, &dev->infos, inode_list, _inode) {
delete_inode(inode->inode);
TAILQ_REMOVE(&dev->infos, inode, inode_list);
if (inode->data) {
free(inode->data);
}
free(inode);
}
/* free device inode */
delete_inode(dev->inode.inode);
/* remove from parent */
TAILQ_REMOVE(&dev->parent->children, dev, siblings);
devman_put_device(dev->parent);
/* free devinfo */
free(dev->info);
/* free device */
free(dev);
return 0;
}

35
servers/devman/devinfo.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef DEVMAN_DEVINFO_H
#define DEVMAN_DEVINFO_H 1
struct devman_dev {
int dev_id;
int parent_dev_id;
char *name;
char *subsys;
void *data;
TAILQ_HEAD(static_attribute_head, devman_static_attribute) attrs;
};
struct devman_static_attribute {
char *name;
char *data;
TAILQ_ENTRY(devman_static_attribute) list;
};
/* used for serializing */
struct devman_device_info {
int count;
int parent_dev_id;
unsigned name_offset;
unsigned subsystem_offset;
};
struct devman_device_info_entry {
unsigned type;
unsigned name_offset;
unsigned data_offset;
unsigned req_nr;
};
#endif

108
servers/devman/devman.h Normal file
View file

@ -0,0 +1,108 @@
#ifndef _SERVERS_DEVMAN_DEVMAN_H
#define _SERVERS_DEVMAN_DEVMAN_H
#define _POSIX_SOURCE 1 /* tell headers to include POSIX stuff */
#define _MINIX 1 /* tell headers to include MINIX stuff */
#define _SYSTEM 1 /* tell headers that this is the kernel */
#define DEVMAN_SERVER 1
#include <minix/config.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <lib.h>
#include <timers.h>
#include <minix/callnr.h>
#include <minix/type.h>
#include <minix/const.h>
#include <minix/com.h>
#include <minix/syslib.h>
#include <minix/sysutil.h>
#include <minix/vfsif.h>
#include <minix/endpoint.h>
#include <minix/sysinfo.h>
#include <minix/u64.h>
#include <minix/sysinfo.h>
#include <minix/type.h>
#include <minix/ipc.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <minix/vtreefs.h>
#include <minix/devman.h>
#include <sys/queue.h>
#define DEVMAN_DEFAULT_MODE (S_IRUSR | S_IRGRP | S_IROTH)
#define DEVMAN_STRING_LEN 128
#define ADD_STRING "ADD "
#define REMOVE_STRING "REMOVE "
enum devman_inode_type {
DEVMAN_DEVINFO_STATIC,
DEVMAN_DEVINFO_DYNAMIC,
DEVMAN_DEVICE
};
typedef int (*devman_read_fn)
(char **ptr, size_t *len, off_t offset, void *data);
struct devman_device_file {
int minor;
int type;
};
struct devman_static_info_inode {
struct devman_device *dev;
char data[DEVMAN_STRING_LEN];
};
struct devman_event {
char data[DEVMAN_STRING_LEN];
TAILQ_ENTRY(devman_event) events;
};
struct devman_event_inode {
TAILQ_HEAD(event_head, devman_event) event_queue;
};
struct devman_inode {
struct inode *inode;
devman_read_fn read_fn;
void *data;
TAILQ_ENTRY(devman_inode) inode_list;
};
struct devman_device {
int dev_id;
char * name;
int ref_count;
int major;
#define DEVMAN_DEVICE_ZOMBIE 2
#define DEVMAN_DEVICE_BOUND 1
#define DEVMAN_DEVICE_UNBOUND 0
int state;
endpoint_t owner;
struct devman_inode inode;
struct devman_device *parent;
/* the serialized information on this device */
struct devman_device_info *info;
TAILQ_ENTRY(devman_device) siblings;
/* devices attached to the this device */
TAILQ_HEAD(children_head, devman_device) children;
TAILQ_HEAD(info_head, devman_inode) infos;
};
#endif

97
servers/devman/main.c Normal file
View file

@ -0,0 +1,97 @@
#define _POSIX_SOURCE 1 /* tell headers to include POSIX stuff */
#define _MINIX 1 /* tell headers to include MINIX stuff */
#define _SYSTEM 1 /* tell headers that this is the kernel */
#include <minix/config.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <lib.h>
#include <timers.h>
#include <minix/callnr.h>
#include <minix/type.h>
#include <minix/const.h>
#include <minix/com.h>
#include <minix/syslib.h>
#include <minix/sysutil.h>
#include <minix/vfsif.h>
#include <minix/endpoint.h>
#include <minix/sysinfo.h>
#include <minix/u64.h>
#include <minix/sysinfo.h>
#include <minix/type.h>
#include <minix/ipc.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <minix/vtreefs.h>
#include "devman.h"
#include "proto.h"
PRIVATE void init_hook(void) {
static int first = 1;
if (first) {
devman_init_devices();
first = 0;
}
}
PRIVATE int message_hook (message *m)
{
switch (m->m_type) {
case DEVMAN_ADD_DEV:
return do_add_device(m);
case DEVMAN_DEL_DEV:
return do_del_device(m);
case DEVMAN_BIND:
return do_bind_device(m);
case DEVMAN_UNBIND:
return do_unbind_device(m);
default: return -1;
}
}
PRIVATE int
read_hook
(struct inode *inode, off_t offset, char **ptr, size_t *len, cbdata_t cbdata)
{
struct devman_inode *d_inode = (struct devman_inode *) cbdata;
return d_inode->read_fn(ptr, len, offset, d_inode->data);
}
PUBLIC int main (int argc, char* argv[])
{
struct fs_hooks hooks;
struct inode_stat root_stat;
/* fill in the hooks */
hooks.init_hook = &init_hook;
hooks.lookup_hook = NULL; /* use the default behavior of lookup */
hooks.getdents_hook = NULL; /* use the default behavior of getdents */
hooks.read_hook = read_hook; /* read hook will never be called */
hooks.rdlink_hook = NULL; /* there are no symbolic links in devfs */
hooks.message_hook = message_hook; /* handle the ds_update call */
root_stat.mode = S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH;
root_stat.uid = 0;
root_stat.gid = 0;
root_stat.size = 0;
root_stat.dev = NO_DEV;
/* limit the number of indexed entries */
start_vtreefs(&hooks, 1024 , &root_stat, 0);
return 0;
}

23
servers/devman/proto.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef _DEVMAN_PROTO_H
#define _DEVMAN_PROTO_H
/* buf.c */
_PROTOTYPE( void buf_init, (off_t start, size_t len) );
_PROTOTYPE( void buf_printf, (char *fmt, ...) );
_PROTOTYPE( void buf_append, (char *data, size_t len) );
_PROTOTYPE( size_t buf_get, (char **ptr) );
/* message handlers */
_PROTOTYPE(int do_add_device, (message *m));
_PROTOTYPE(int do_del_device, (message *m));
_PROTOTYPE(int do_bind_device, (message *m));
_PROTOTYPE(int do_unbind_device, (message *m));
/* local helper functions */
_PROTOTYPE(void devman_init_devices, ());
_PROTOTYPE(struct devman_device* devman_find_device,(int devid));
_PROTOTYPE(void devman_get_device, (struct devman_device *dev));
_PROTOTYPE(void devman_put_device, (struct devman_device *dev));
#endif /* _DEVMAN_PROTO_H */