From: Dirk Vogt Date: Fri, 25 Feb 2011 12:28:07 +0000 (+0000) Subject: libdevman: IPC wrapper for devman X-Git-Tag: v3.2.0~638 X-Git-Url: http://zhaoyanbai.com/repos/icons/debian/static/man.7.txt?a=commitdiff_plain;h=8c8e44d0ae07ab0eb14eabbf2765154d4e9ef56c;p=minix.git libdevman: IPC wrapper for devman --- diff --git a/lib/Makefile b/lib/Makefile index b66909371..4f7e8ba59 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,8 +1,8 @@ .include SUBDIR= csu libc libcurses libdriver libnetdriver libedit libm libsys \ - libtimers libutil libbz2 libl libhgfs libz libfetch libarchive \ - libvtreefs libaudiodriver libmthread libexec libusb + libtimers libutil libbz2 libl libhgfs libz libfetch libarchive \ + libvtreefs libaudiodriver libmthread libexec libdevman libusb .if ${COMPILER_TYPE} == "ack" SUBDIR+= ack/libd ack/libe ack/libfp ack/liby diff --git a/lib/libdevman/Makefile b/lib/libdevman/Makefile new file mode 100644 index 000000000..d5fc0f9b0 --- /dev/null +++ b/lib/libdevman/Makefile @@ -0,0 +1,8 @@ +LIB = devman + +SRCS = generic.c \ + usb.c + +.include + + diff --git a/lib/libdevman/generic.c b/lib/libdevman/generic.c new file mode 100644 index 000000000..d8d3e7649 --- /dev/null +++ b/lib/libdevman/generic.c @@ -0,0 +1,280 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "local.h" + +PRIVATE endpoint_t devman_ep; + +FORWARD _PROTOTYPE( int save_string, + (char *buffer, char *src, size_t *offset)); + +PRIVATE TAILQ_HEAD(devlist_head, devman_dev) dev_list; + +/**************************************************************************** + * save_string * + ***************************************************************************/ +PRIVATE int save_string(char *buffer, char *src, size_t *offset) +{ + unsigned old_offset = *offset; + size_t len = strlen(src) + 1; + memcpy(buffer + *offset, src, len); + *offset += len; + return old_offset; +} + +/**************************************************************************** + * serialize_dev * + ***************************************************************************/ +PUBLIC void *serialize_dev(struct devman_dev *dev, size_t *overall_size) +{ + /* determine size of serialized version of dev */ + char *buffer; + char *string_buffer; + size_t string_buffer_offset; + size_t count = 0; + size_t size = sizeof(struct devman_device_info); + size_t strings_size = strlen(dev->name) + 1; + struct devman_device_info * serialized_dev; + struct devman_device_info_entry *entry; + struct devman_static_attribute *attribute; + + TAILQ_FOREACH(attribute, &dev->attrs, list) { + strings_size += strlen(attribute->name) + 1; + strings_size += strlen(attribute->data) + 1; + size += sizeof(struct devman_device_info_entry); + count++; + } + + buffer = malloc(size + strings_size); + + if (buffer == NULL) { + return NULL; + } + + string_buffer = buffer; + string_buffer_offset = size; /* strings start after + devman_device_info and + devman_device_info_entries */ + + /* serialize device */ + serialized_dev = (struct devman_device_info *) buffer; + + serialized_dev->count = count; + serialized_dev->parent_dev_id = dev->parent_dev_id; + serialized_dev->name_offset = + save_string(string_buffer, dev->name, &string_buffer_offset); +#if 0 + serialized_dev->bus = + save_string(string_buffer, dev->bus, &string_buffer_offset); +#endif + + /* serialize entries */ + entry = + (struct devman_device_info_entry *) + (buffer + sizeof(struct devman_device_info)); + + TAILQ_FOREACH(attribute, &dev->attrs, list) { + entry->type = 0; /* TODO: use macro */ + entry->name_offset = + save_string(string_buffer, attribute->name, &string_buffer_offset); + entry->data_offset = + save_string(string_buffer, attribute->data, &string_buffer_offset); + entry++; + } + + *overall_size = size + strings_size; + + return buffer; + +} + +/**************************************************************************** + * devman_add_device * + ***************************************************************************/ +PUBLIC int devman_add_device(struct devman_dev *dev) +{ + message msg; + int res; + size_t grant_size; + void *buf = serialize_dev(dev, &grant_size); + + cp_grant_id_t gid = + cpf_grant_direct(devman_ep,(vir_bytes) buf, + grant_size, CPF_READ); + + /* prepare message */ + msg.m_type = DEVMAN_ADD_DEV; + msg.DEVMAN_GRANT_ID = gid; + msg.DEVMAN_GRANT_SIZE = grant_size; + + /* send message */ + res = sendrec(devman_ep, &msg); + + if (res != 0) { + panic("devman_add_device: could not talk to devman: %d", res); + } + + if (msg.m_type != DEVMAN_REPLY) { + panic("devman_add_device: got illegal response from devman: %d", + msg.m_type); + } + + if (msg.DEVMAN_RESULT != 0) { + panic("devman_add_device: could add device: %d", + msg.DEVMAN_RESULT); + } + + /* store given dev_id to dev */ + dev->dev_id = msg.DEVMAN_DEVICE_ID; + + cpf_revoke(gid); + + free(buf); + + /* put device in list */ + TAILQ_INSERT_HEAD(&dev_list, dev, dev_list); + + return 0; +} + +/**************************************************************************** + * devman_del_device * + ***************************************************************************/ +PUBLIC int devman_del_device(struct devman_dev *dev) +{ + message msg; + int res; + + msg.m_type = DEVMAN_DEL_DEV; + msg.DEVMAN_DEVICE_ID = dev->dev_id; + + res = sendrec(devman_ep, &msg); + + if (res != 0) { + panic("devman_del_device: could not talk to devman: %d", res); + } + + if (msg.m_type != DEVMAN_REPLY) { + panic("devman_del_device: got illegal response from devman: %d", + msg.m_type); + } + + if (msg.DEVMAN_RESULT != 0) { + panic("devman_del_device: could delete device: %d", + msg.DEVMAN_RESULT); + } + + /* remove the device from list */ + TAILQ_REMOVE(&dev_list, dev, dev_list); + + return 0; + +} + +/**************************************************************************** + * devman_get_ep * + ***************************************************************************/ +PUBLIC endpoint_t devman_get_ep() +{ + return devman_ep; +} + +/**************************************************************************** + * devman_init * + ***************************************************************************/ +PUBLIC int devman_init() +{ + int res; + message msg; + + /* get the endpoint of the HCD */ + res = ds_retrieve_label_endpt("devman", &devman_ep); + + if (res != 0) { + panic("usb_init: ds_retrieve_label_endpt failed for 'devman': %d", res); + } + + TAILQ_INIT(&dev_list); + + return res; +} + +/**************************************************************************** + * do_bind * + ***************************************************************************/ +PRIVATE void do_bind(message *m) +{ + struct devman_dev *dev; + int res; + + /* find device */ + TAILQ_FOREACH(dev, &dev_list, dev_list) { + if (dev->dev_id == m->DEVMAN_DEVICE_ID) { + if (dev->bind_cb) { + res = dev->bind_cb(dev->data, m->DEVMAN_ENDPOINT); + m->m_type = DEVMAN_REPLY; + m->DEVMAN_RESULT = res; + send(devman_ep, m); + return; + } + } + } + m->m_type = DEVMAN_REPLY; + m->DEVMAN_RESULT = ENODEV; + send(devman_ep, m); + return; +} + +/**************************************************************************** + * do_unbind * + ***************************************************************************/ +PRIVATE int do_unbind(message *m) +{ + struct devman_dev *dev; + int res; + + /* find device */ + TAILQ_FOREACH(dev, &dev_list, dev_list) { + if (dev->dev_id == m->DEVMAN_DEVICE_ID) { + if (dev->unbind_cb) { + res = dev->unbind_cb(dev->data, m->DEVMAN_ENDPOINT); + m->m_type = DEVMAN_REPLY; + m->DEVMAN_RESULT = res; + send(devman_ep, m); + return; + } + } + } + m->m_type = DEVMAN_REPLY; + m->DEVMAN_RESULT = ENODEV; + send(devman_ep, m); +} + +/**************************************************************************** + * devman_handle_msg * + ***************************************************************************/ +PUBLIC int devman_handle_msg(message *m) +{ + /* make sure msg comes from devman server */ + if (m->m_source != devman_ep) { + /* we don't honor requests from others by answering them */ + return 0; + } + switch (m->m_type) { + case DEVMAN_BIND: + do_bind(m); + return 1; + case DEVMAN_UNBIND: + do_unbind(m); + return 1; + default: + return 0; + } +} diff --git a/lib/libdevman/local.h b/lib/libdevman/local.h new file mode 100644 index 000000000..3af4268b4 --- /dev/null +++ b/lib/libdevman/local.h @@ -0,0 +1,27 @@ +#ifndef _LIB_LIBDEVMAN_LOCAL +#define _LIB_LIBDEVMAN_LOCAL + +#include +#include + +#define DEVMAN_DEV_NAME_LEN 32 + +struct devman_dev { + int dev_id; + int parent_dev_id; + char name[DEVMAN_DEV_NAME_LEN]; + char *subsys; + void *data; + int (*bind_cb) (void *data, endpoint_t ep); + int (*unbind_cb)(void *data, endpoint_t ep); + TAILQ_HEAD(static_attribute_head, devman_static_attribute) attrs; + TAILQ_ENTRY(devman_dev) dev_list; +}; + +struct devman_static_attribute { + char *name; + char *data; + TAILQ_ENTRY(devman_static_attribute) list; +}; + +#endif diff --git a/lib/libdevman/usb.c b/lib/libdevman/usb.c new file mode 100644 index 000000000..c0f9a888c --- /dev/null +++ b/lib/libdevman/usb.c @@ -0,0 +1,300 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "local.h" + +#define CHECKOUTOFMEM(ptr) if(ptr == NULL) \ + panic("Out of memory! (%s, line %d)" \ + __FILE__, __LINE__) + + +static int (*bind_cb) (struct devman_usb_bind_cb_data *data, endpoint_t ep); +static int (*unbind_cb) (struct devman_usb_bind_cb_data *data, endpoint_t ep); + +/**************************************************************************** + * devman_usb_add_attr * + ***************************************************************************/ +PRIVATE void +devman_usb_add_attr +(struct devman_dev *dev, char *name, char *data) +{ + struct devman_static_attribute *attr = (struct devman_static_attribute *) + malloc(sizeof(struct devman_static_attribute)); + + CHECKOUTOFMEM(attr); + + attr->name = malloc((strlen(name)+1)*sizeof(char)); + memcpy(attr->name, name, (strlen(name)+1)); + + attr->data = malloc((strlen(data)+1)*sizeof(char)); + memcpy(attr->data, data, (strlen(data)+1)); + TAILQ_INSERT_TAIL(&dev->attrs, attr, list); +} + +/**************************************************************************** + * add_device_attributes * + ***************************************************************************/ +PRIVATE void +add_device_attributes +(struct devman_usb_dev *udev) +{ + int ret; + char data[32]; + + ret = sprintf(data,"0x%02x",udev->desc->bDeviceClass); + if (ret < 0) { + panic("add_device_attributes: sprintf failed"); + } + devman_usb_add_attr(udev->dev, "bDeviceClass", data); + + ret = sprintf(data,"0x%02x",udev->desc->bDeviceSubClass); + if (ret < 0) { + panic("add_device_attributes: sprintf failed"); + } + devman_usb_add_attr(udev->dev, "bDeviceSubClass", data); + + ret = sprintf(data,"0x%02x",udev->desc->bDeviceProtocol); + if (ret < 0) { + panic("add_device_attributes: sprintf failed"); + } + devman_usb_add_attr(udev->dev, "bDeviceProtocol", data); + + ret = sprintf(data,"0x%04x",UGETW(udev->desc->idVendor)); + if (ret < 0) { + panic("add_device_attributes: sprintf failed"); + } + devman_usb_add_attr(udev->dev, "idVendor", data); + + ret = sprintf(data,"0x%04x",UGETW(udev->desc->idProduct)); + if (ret < 0) { + panic("add_device_attributes: sprintf failed"); + } + devman_usb_add_attr(udev->dev, "idProduct", data); + + if (udev->product) + devman_usb_add_attr(udev->dev, "Product", udev->product); + if (udev->manufacturer) + devman_usb_add_attr(udev->dev, "Manufacturer", udev->manufacturer); + if (udev->serial) + devman_usb_add_attr(udev->dev, "SerialNumber", udev->serial); + devman_usb_add_attr(udev->dev, "dev_type", "USB_DEV"); +} + +/**************************************************************************** + * add_interface_attributes * + ***************************************************************************/ +PRIVATE void +add_interface_attributes +(struct devman_usb_interface *intf) +{ + int ret; + char data[32]; + + ret = sprintf(data,"0x%02x",intf->desc->bInterfaceNumber); + if (ret < 0) { + panic("add_device_attributes: sprintf failed"); + } + devman_usb_add_attr(intf->dev, "bInterfaceNumber", data); + + ret = sprintf(data,"0x%02x",intf->desc->bAlternateSetting); + if (ret < 0) { + panic("add_device_attributes: sprintf failed"); + } + devman_usb_add_attr(intf->dev, "bAlternateSetting", data); + + ret = sprintf(data,"0x%02x",intf->desc->bNumEndpoints); + if (ret < 0) { + panic("add_device_attributes: sprintf failed"); + } + devman_usb_add_attr(intf->dev, "bNumEndpoints", data); + + ret = sprintf(data,"0x%02x",intf->desc->bInterfaceClass); + if (ret < 0) { + panic("add_device_attributes: sprintf failed"); + } + devman_usb_add_attr(intf->dev, "bInterfaceClass", data); + + ret = sprintf(data,"0x%02x",intf->desc->bInterfaceSubClass); + if (ret < 0) { + panic("add_device_attributes: sprintf failed"); + } + devman_usb_add_attr(intf->dev, "bInterfaceSubClass", data); + + ret = sprintf(data,"0x%02x",intf->desc->bInterfaceProtocol); + if (ret < 0) { + panic("add_device_attributes: sprintf failed"); + } + devman_usb_add_attr(intf->dev, "bInterfaceProtocol", data); + + devman_usb_add_attr(intf->dev, "dev_type", "USB_INTF"); +} + + +/**************************************************************************** + * devman_usb_device_new * + ***************************************************************************/ +PUBLIC struct devman_usb_dev* +devman_usb_device_new +(int dev_id) +{ + struct devman_usb_dev *udev = NULL; + struct devman_dev * dev = NULL; + + udev = (struct devman_usb_dev *) malloc(sizeof(struct devman_usb_dev)); + + CHECKOUTOFMEM(udev); + + /* allocate device */ + dev = (struct devman_dev *) malloc(sizeof(struct devman_dev)); + + CHECKOUTOFMEM(dev); + + udev->dev_id = dev_id; + udev->dev = dev; + + dev->parent_dev_id = 0; /* For now add it directly to the root dev */ + + snprintf(dev->name, DEVMAN_DEV_NAME_LEN, "USB%d", dev_id); + + TAILQ_INIT(&dev->attrs); + + return udev; +} + +/**************************************************************************** + * devman_usb_device_delete * + ***************************************************************************/ +PUBLIC void devman_usb_device_delete(struct devman_usb_dev *udev) +{ + int i; + struct devman_static_attribute *attr,*temp; + + + for (i=0; i < udev->intf_count; i++) { + TAILQ_FOREACH_SAFE(attr, &udev->interfaces[i].dev->attrs, list, temp) + { + free(attr->name); + free(attr->data); + free(attr); + } + free(udev->interfaces[i].dev); + } + + TAILQ_FOREACH_SAFE(attr, &udev->dev->attrs, list, temp) { + free(attr->name); + free(attr->data); + free(attr); + } + + free(udev->dev); + free(udev); +} + +PRIVATE int devman_usb_bind_cb(void *data, endpoint_t ep) { + if (bind_cb) { + return bind_cb((struct devman_usb_bind_cb_data *) data, ep); + } else { + return ENODEV; + } +} + +PRIVATE int devman_usb_unbind_cb(void *data, endpoint_t ep) { + if (unbind_cb) { + return unbind_cb((struct devman_usb_bind_cb_data *) data, ep); + } else { + return ENODEV; + } +} + +/**************************************************************************** + * devman_usb_device_add * + ***************************************************************************/ +PUBLIC int devman_usb_device_add(struct devman_usb_dev *dev) +{ + int i,res = 0; + add_device_attributes(dev); + + /* add the USB device */ + dev->cb_data.dev_id = dev->dev_id; + dev->cb_data.interface = -1; + + dev->dev->bind_cb = devman_usb_bind_cb; + dev->dev->unbind_cb = devman_usb_unbind_cb; + dev->dev->data = &dev->cb_data; + + res = devman_add_device(dev->dev); + + if (res != 0) { + panic("devman_usb_device_add(): devman_add_device failed."); + } + + /* add the USB interfaces */ + for (i=0; i < dev->intf_count; i++) { + /* prepare */ + dev->interfaces[i].dev = + (struct devman_dev *) malloc(sizeof(struct devman_dev)); + CHECKOUTOFMEM(dev->interfaces[i].dev); + + TAILQ_INIT(&dev->interfaces[i].dev->attrs); + snprintf(dev->interfaces[i].dev->name, DEVMAN_DEV_NAME_LEN, + "intf%d", i); + + add_interface_attributes(&dev->interfaces[i]); + + dev->interfaces[i].dev->parent_dev_id = dev->dev->dev_id; + + + dev->interfaces[i].cb_data.dev_id = dev->dev_id; + dev->interfaces[i].cb_data.interface = + dev->interfaces[i].desc->bInterfaceNumber; + + dev->interfaces[i].dev->bind_cb = devman_usb_bind_cb; + dev->interfaces[i].dev->unbind_cb = devman_usb_unbind_cb; + dev->interfaces[i].dev->data = &dev->interfaces[i].cb_data; + + /* add */ + res = devman_add_device(dev->interfaces[i].dev); + + if (res != 0) { + panic("devman_usb_device_add(): devman_add_device failed."); + } + } + + return res; +} + +/**************************************************************************** + * devman_usb_device_remove * + ***************************************************************************/ +PUBLIC int devman_usb_device_remove(struct devman_usb_dev *dev) +{ + int i, res = 0; + + for (i=0; i < dev->intf_count; i++) { + + res = devman_del_device(dev->interfaces[i].dev); + + if (res != 0) { + panic("devman_usb_device_remove(): devman_del_device failed."); + } + } + res = devman_del_device(dev->dev); + return res; +} + +/**************************************************************************** + * devman_usb_init * + ***************************************************************************/ +PUBLIC int devman_usb_init +(int (*_bind_cb) (struct devman_usb_bind_cb_data *data, endpoint_t ep), + int (*_unbind_cb) (struct devman_usb_bind_cb_data *data, endpoint_t ep)) +{ + bind_cb = _bind_cb; + unbind_cb = _unbind_cb; +} diff --git a/share/mk/bsd.prog.mk b/share/mk/bsd.prog.mk index d98ce8cd5..cc337be9a 100644 --- a/share/mk/bsd.prog.mk +++ b/share/mk/bsd.prog.mk @@ -59,7 +59,7 @@ MKDEP_SUFFIXES?= .o .ln # rumpfs_tmpfs rumpfs_udf rumpfs_ufs .for _lib in \ c curses driver netdriver edit end m sys timers util bz2 l hgfs \ - audiodriver exec usb + audiodriver exec devman usb .ifndef LIB${_lib:tu} LIB${_lib:tu}= ${DESTDIR}/usr/lib/lib${_lib}.a .if ${COMPILER_TYPE} == "ack"