]> Zhao Yanbai Git Server - minix.git/commitdiff
libdevman: IPC wrapper for devman
authorDirk Vogt <dirk@minix3.org>
Fri, 25 Feb 2011 12:28:07 +0000 (12:28 +0000)
committerDirk Vogt <dirk@minix3.org>
Fri, 25 Feb 2011 12:28:07 +0000 (12:28 +0000)
lib/Makefile
lib/libdevman/Makefile [new file with mode: 0644]
lib/libdevman/generic.c [new file with mode: 0644]
lib/libdevman/local.h [new file with mode: 0644]
lib/libdevman/usb.c [new file with mode: 0644]
share/mk/bsd.prog.mk

index b669093717b4baf25a2043a907ac5b32356e33e9..4f7e8ba59bde4f9e2cce4a72cd1c0334e43d2d2d 100644 (file)
@@ -1,8 +1,8 @@
 .include <bsd.own.mk>
 
 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 (file)
index 0000000..d5fc0f9
--- /dev/null
@@ -0,0 +1,8 @@
+LIB = devman
+
+SRCS = generic.c \
+       usb.c
+
+.include <bsd.lib.mk>
+
+
diff --git a/lib/libdevman/generic.c b/lib/libdevman/generic.c
new file mode 100644 (file)
index 0000000..d8d3e76
--- /dev/null
@@ -0,0 +1,280 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <minix/com.h>
+#include <minix/ipc.h>
+#include <minix/const.h>
+#include <minix/devman.h>
+#include <minix/safecopies.h>
+
+#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 (file)
index 0000000..3af4268
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _LIB_LIBDEVMAN_LOCAL
+#define _LIB_LIBDEVMAN_LOCAL
+
+#include <sys/queue.h>
+#include <minix/com.h>
+
+#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 (file)
index 0000000..c0f9a88
--- /dev/null
@@ -0,0 +1,300 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <minix/config.h>
+#include <minix/const.h>
+#include <minix/devman.h>
+#include <minix/usb.h>
+
+#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;
+}
index d98ce8cd5ff5b7eb7c054d06decbab739c34ae14..cc337be9ae07a52c19d1e227b619a9cab81abfdc 100644 (file)
@@ -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"