2011-02-25 13:28:07 +01:00
|
|
|
#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>
|
2011-11-14 11:07:49 +01:00
|
|
|
#include <minix/sysutil.h>
|
2011-02-25 13:28:07 +01:00
|
|
|
|
|
|
|
#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 *
|
|
|
|
***************************************************************************/
|
2012-03-25 20:25:53 +02:00
|
|
|
static void
|
2011-02-25 13:28:07 +01:00
|
|
|
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 *
|
|
|
|
***************************************************************************/
|
2012-03-25 20:25:53 +02:00
|
|
|
static void
|
2011-02-25 13:28:07 +01:00
|
|
|
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 *
|
|
|
|
***************************************************************************/
|
2012-03-25 20:25:53 +02:00
|
|
|
static void
|
2011-02-25 13:28:07 +01:00
|
|
|
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 *
|
|
|
|
***************************************************************************/
|
2012-03-25 20:25:53 +02:00
|
|
|
struct devman_usb_dev*
|
2011-02-25 13:28:07 +01:00
|
|
|
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 *
|
|
|
|
***************************************************************************/
|
2012-03-25 20:25:53 +02:00
|
|
|
void devman_usb_device_delete(struct devman_usb_dev *udev)
|
2011-02-25 13:28:07 +01:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-03-25 20:25:53 +02:00
|
|
|
static int devman_usb_bind_cb(void *data, endpoint_t ep) {
|
2011-02-25 13:28:07 +01:00
|
|
|
if (bind_cb) {
|
|
|
|
return bind_cb((struct devman_usb_bind_cb_data *) data, ep);
|
|
|
|
} else {
|
|
|
|
return ENODEV;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-25 20:25:53 +02:00
|
|
|
static int devman_usb_unbind_cb(void *data, endpoint_t ep) {
|
2011-02-25 13:28:07 +01:00
|
|
|
if (unbind_cb) {
|
|
|
|
return unbind_cb((struct devman_usb_bind_cb_data *) data, ep);
|
|
|
|
} else {
|
|
|
|
return ENODEV;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* devman_usb_device_add *
|
|
|
|
***************************************************************************/
|
2012-03-25 20:25:53 +02:00
|
|
|
int devman_usb_device_add(struct devman_usb_dev *dev)
|
2011-02-25 13:28:07 +01:00
|
|
|
{
|
|
|
|
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 *
|
|
|
|
***************************************************************************/
|
2012-03-25 20:25:53 +02:00
|
|
|
int devman_usb_device_remove(struct devman_usb_dev *dev)
|
2011-02-25 13:28:07 +01:00
|
|
|
{
|
|
|
|
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 *
|
|
|
|
***************************************************************************/
|
2012-03-25 20:25:53 +02:00
|
|
|
void devman_usb_init
|
2011-02-25 13:28:07 +01:00
|
|
|
(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;
|
|
|
|
}
|