1433d6423SLionel Sambuc #include <errno.h>
2433d6423SLionel Sambuc #include <stdio.h>
3433d6423SLionel Sambuc #include <stdlib.h>
4433d6423SLionel Sambuc #include <string.h>
5433d6423SLionel Sambuc #include <minix/config.h>
6433d6423SLionel Sambuc #include <minix/const.h>
7433d6423SLionel Sambuc #include <minix/devman.h>
8433d6423SLionel Sambuc #include <minix/usb.h>
9433d6423SLionel Sambuc #include <minix/sysutil.h>
10433d6423SLionel Sambuc
11433d6423SLionel Sambuc #include "local.h"
12433d6423SLionel Sambuc
13433d6423SLionel Sambuc #define CHECKOUTOFMEM(ptr) if(ptr == NULL) \
14433d6423SLionel Sambuc panic("Out of memory! (%s, line %d)", \
15433d6423SLionel Sambuc __FILE__, __LINE__)
16433d6423SLionel Sambuc
17433d6423SLionel Sambuc
18433d6423SLionel Sambuc static int (*bind_cb) (struct devman_usb_bind_cb_data *data, endpoint_t ep);
19433d6423SLionel Sambuc static int (*unbind_cb) (struct devman_usb_bind_cb_data *data, endpoint_t ep);
20433d6423SLionel Sambuc
21433d6423SLionel Sambuc /****************************************************************************
22433d6423SLionel Sambuc * devman_usb_add_attr *
23433d6423SLionel Sambuc ***************************************************************************/
24433d6423SLionel Sambuc static void
devman_usb_add_attr(struct devman_dev * dev,const char * name,const char * data)25433d6423SLionel Sambuc devman_usb_add_attr
2665f76edbSDavid van Moolenbroek (struct devman_dev *dev, const char *name, const char *data)
27433d6423SLionel Sambuc {
28433d6423SLionel Sambuc struct devman_static_attribute *attr = (struct devman_static_attribute *)
29433d6423SLionel Sambuc malloc(sizeof(struct devman_static_attribute));
30433d6423SLionel Sambuc
31433d6423SLionel Sambuc CHECKOUTOFMEM(attr);
32433d6423SLionel Sambuc
33433d6423SLionel Sambuc attr->name = malloc((strlen(name)+1)*sizeof(char));
34433d6423SLionel Sambuc memcpy(attr->name, name, (strlen(name)+1));
35433d6423SLionel Sambuc
36433d6423SLionel Sambuc attr->data = malloc((strlen(data)+1)*sizeof(char));
37433d6423SLionel Sambuc memcpy(attr->data, data, (strlen(data)+1));
38433d6423SLionel Sambuc TAILQ_INSERT_TAIL(&dev->attrs, attr, list);
39433d6423SLionel Sambuc }
40433d6423SLionel Sambuc
41433d6423SLionel Sambuc /****************************************************************************
42433d6423SLionel Sambuc * add_device_attributes *
43433d6423SLionel Sambuc ***************************************************************************/
44433d6423SLionel Sambuc static void
add_device_attributes(struct devman_usb_dev * udev)45433d6423SLionel Sambuc add_device_attributes
46433d6423SLionel Sambuc (struct devman_usb_dev *udev)
47433d6423SLionel Sambuc {
48433d6423SLionel Sambuc int ret;
49433d6423SLionel Sambuc char data[32];
50433d6423SLionel Sambuc
51*0a6a1f1dSLionel Sambuc ret = snprintf(data,sizeof(data),"0x%02x",udev->desc->bDeviceClass);
52433d6423SLionel Sambuc if (ret < 0) {
53*0a6a1f1dSLionel Sambuc panic("add_device_attributes: snprintf failed");
54433d6423SLionel Sambuc }
55433d6423SLionel Sambuc devman_usb_add_attr(udev->dev, "bDeviceClass", data);
56433d6423SLionel Sambuc
57*0a6a1f1dSLionel Sambuc ret = snprintf(data,sizeof(data),"0x%02x",udev->desc->bDeviceSubClass);
58433d6423SLionel Sambuc if (ret < 0) {
59*0a6a1f1dSLionel Sambuc panic("add_device_attributes: snprintf failed");
60433d6423SLionel Sambuc }
61433d6423SLionel Sambuc devman_usb_add_attr(udev->dev, "bDeviceSubClass", data);
62433d6423SLionel Sambuc
63*0a6a1f1dSLionel Sambuc ret = snprintf(data,sizeof(data),"0x%02x",udev->desc->bDeviceProtocol);
64433d6423SLionel Sambuc if (ret < 0) {
65*0a6a1f1dSLionel Sambuc panic("add_device_attributes: snprintf failed");
66433d6423SLionel Sambuc }
67433d6423SLionel Sambuc devman_usb_add_attr(udev->dev, "bDeviceProtocol", data);
68433d6423SLionel Sambuc
69*0a6a1f1dSLionel Sambuc ret = snprintf(data,sizeof(data),"0x%04x",UGETW(udev->desc->idVendor));
70433d6423SLionel Sambuc if (ret < 0) {
71*0a6a1f1dSLionel Sambuc panic("add_device_attributes: snprintf failed");
72433d6423SLionel Sambuc }
73433d6423SLionel Sambuc devman_usb_add_attr(udev->dev, "idVendor", data);
74433d6423SLionel Sambuc
75*0a6a1f1dSLionel Sambuc ret = snprintf(data,sizeof(data),"0x%04x",UGETW(udev->desc->idProduct));
76433d6423SLionel Sambuc if (ret < 0) {
77*0a6a1f1dSLionel Sambuc panic("add_device_attributes: snprintf failed");
78433d6423SLionel Sambuc }
79433d6423SLionel Sambuc devman_usb_add_attr(udev->dev, "idProduct", data);
80433d6423SLionel Sambuc
81433d6423SLionel Sambuc if (udev->product)
82433d6423SLionel Sambuc devman_usb_add_attr(udev->dev, "Product", udev->product);
83433d6423SLionel Sambuc if (udev->manufacturer)
84433d6423SLionel Sambuc devman_usb_add_attr(udev->dev, "Manufacturer", udev->manufacturer);
85433d6423SLionel Sambuc if (udev->serial)
86433d6423SLionel Sambuc devman_usb_add_attr(udev->dev, "SerialNumber", udev->serial);
87433d6423SLionel Sambuc devman_usb_add_attr(udev->dev, "dev_type", "USB_DEV");
88433d6423SLionel Sambuc }
89433d6423SLionel Sambuc
90433d6423SLionel Sambuc /****************************************************************************
91433d6423SLionel Sambuc * add_interface_attributes *
92433d6423SLionel Sambuc ***************************************************************************/
93433d6423SLionel Sambuc static void
add_interface_attributes(struct devman_usb_interface * intf)94433d6423SLionel Sambuc add_interface_attributes
95433d6423SLionel Sambuc (struct devman_usb_interface *intf)
96433d6423SLionel Sambuc {
97433d6423SLionel Sambuc int ret;
98433d6423SLionel Sambuc char data[32];
99433d6423SLionel Sambuc
100*0a6a1f1dSLionel Sambuc ret = snprintf(data,sizeof(data),"0x%02x",intf->desc->bInterfaceNumber);
101433d6423SLionel Sambuc if (ret < 0) {
102*0a6a1f1dSLionel Sambuc panic("add_device_attributes: snprintf failed");
103433d6423SLionel Sambuc }
104433d6423SLionel Sambuc devman_usb_add_attr(intf->dev, "bInterfaceNumber", data);
105433d6423SLionel Sambuc
106*0a6a1f1dSLionel Sambuc ret = snprintf(data,sizeof(data),"0x%02x",intf->desc->bAlternateSetting);
107433d6423SLionel Sambuc if (ret < 0) {
108*0a6a1f1dSLionel Sambuc panic("add_device_attributes: snprintf failed");
109433d6423SLionel Sambuc }
110433d6423SLionel Sambuc devman_usb_add_attr(intf->dev, "bAlternateSetting", data);
111433d6423SLionel Sambuc
112*0a6a1f1dSLionel Sambuc ret = snprintf(data,sizeof(data),"0x%02x",intf->desc->bNumEndpoints);
113433d6423SLionel Sambuc if (ret < 0) {
114*0a6a1f1dSLionel Sambuc panic("add_device_attributes: snprintf failed");
115433d6423SLionel Sambuc }
116433d6423SLionel Sambuc devman_usb_add_attr(intf->dev, "bNumEndpoints", data);
117433d6423SLionel Sambuc
118*0a6a1f1dSLionel Sambuc ret = snprintf(data,sizeof(data),"0x%02x",intf->desc->bInterfaceClass);
119433d6423SLionel Sambuc if (ret < 0) {
120*0a6a1f1dSLionel Sambuc panic("add_device_attributes: snprintf failed");
121433d6423SLionel Sambuc }
122433d6423SLionel Sambuc devman_usb_add_attr(intf->dev, "bInterfaceClass", data);
123433d6423SLionel Sambuc
124*0a6a1f1dSLionel Sambuc ret = snprintf(data,sizeof(data),"0x%02x",intf->desc->bInterfaceSubClass);
125433d6423SLionel Sambuc if (ret < 0) {
126*0a6a1f1dSLionel Sambuc panic("add_device_attributes: snprintf failed");
127433d6423SLionel Sambuc }
128433d6423SLionel Sambuc devman_usb_add_attr(intf->dev, "bInterfaceSubClass", data);
129433d6423SLionel Sambuc
130*0a6a1f1dSLionel Sambuc ret = snprintf(data,sizeof(data),"0x%02x",intf->desc->bInterfaceProtocol);
131433d6423SLionel Sambuc if (ret < 0) {
132*0a6a1f1dSLionel Sambuc panic("add_device_attributes: snprintf failed");
133433d6423SLionel Sambuc }
134433d6423SLionel Sambuc devman_usb_add_attr(intf->dev, "bInterfaceProtocol", data);
135433d6423SLionel Sambuc
136433d6423SLionel Sambuc devman_usb_add_attr(intf->dev, "dev_type", "USB_INTF");
137433d6423SLionel Sambuc }
138433d6423SLionel Sambuc
139433d6423SLionel Sambuc
140433d6423SLionel Sambuc /****************************************************************************
141433d6423SLionel Sambuc * devman_usb_device_new *
142433d6423SLionel Sambuc ***************************************************************************/
143433d6423SLionel Sambuc struct devman_usb_dev*
devman_usb_device_new(int dev_id)144433d6423SLionel Sambuc devman_usb_device_new
145433d6423SLionel Sambuc (int dev_id)
146433d6423SLionel Sambuc {
147433d6423SLionel Sambuc struct devman_usb_dev *udev = NULL;
148433d6423SLionel Sambuc struct devman_dev * dev = NULL;
149433d6423SLionel Sambuc
150433d6423SLionel Sambuc udev = (struct devman_usb_dev *) malloc(sizeof(struct devman_usb_dev));
151433d6423SLionel Sambuc
152433d6423SLionel Sambuc CHECKOUTOFMEM(udev);
153433d6423SLionel Sambuc
154433d6423SLionel Sambuc /* allocate device */
155433d6423SLionel Sambuc dev = (struct devman_dev *) malloc(sizeof(struct devman_dev));
156433d6423SLionel Sambuc
157433d6423SLionel Sambuc CHECKOUTOFMEM(dev);
158433d6423SLionel Sambuc
159433d6423SLionel Sambuc udev->dev_id = dev_id;
160433d6423SLionel Sambuc udev->dev = dev;
161433d6423SLionel Sambuc
162433d6423SLionel Sambuc dev->parent_dev_id = 0; /* For now add it directly to the root dev */
163433d6423SLionel Sambuc
164433d6423SLionel Sambuc snprintf(dev->name, DEVMAN_DEV_NAME_LEN, "USB%d", dev_id);
165433d6423SLionel Sambuc
166433d6423SLionel Sambuc TAILQ_INIT(&dev->attrs);
167433d6423SLionel Sambuc
168433d6423SLionel Sambuc return udev;
169433d6423SLionel Sambuc }
170433d6423SLionel Sambuc
171433d6423SLionel Sambuc /****************************************************************************
172433d6423SLionel Sambuc * devman_usb_device_delete *
173433d6423SLionel Sambuc ***************************************************************************/
devman_usb_device_delete(struct devman_usb_dev * udev)174433d6423SLionel Sambuc void devman_usb_device_delete(struct devman_usb_dev *udev)
175433d6423SLionel Sambuc {
176433d6423SLionel Sambuc int i;
177433d6423SLionel Sambuc struct devman_static_attribute *attr,*temp;
178433d6423SLionel Sambuc
179433d6423SLionel Sambuc
180433d6423SLionel Sambuc for (i=0; i < udev->intf_count; i++) {
181433d6423SLionel Sambuc TAILQ_FOREACH_SAFE(attr, &udev->interfaces[i].dev->attrs, list, temp)
182433d6423SLionel Sambuc {
183433d6423SLionel Sambuc free(attr->name);
184433d6423SLionel Sambuc free(attr->data);
185433d6423SLionel Sambuc free(attr);
186433d6423SLionel Sambuc }
187433d6423SLionel Sambuc free(udev->interfaces[i].dev);
188433d6423SLionel Sambuc }
189433d6423SLionel Sambuc
190433d6423SLionel Sambuc TAILQ_FOREACH_SAFE(attr, &udev->dev->attrs, list, temp) {
191433d6423SLionel Sambuc free(attr->name);
192433d6423SLionel Sambuc free(attr->data);
193433d6423SLionel Sambuc free(attr);
194433d6423SLionel Sambuc }
195433d6423SLionel Sambuc
196433d6423SLionel Sambuc free(udev->dev);
197433d6423SLionel Sambuc free(udev);
198433d6423SLionel Sambuc }
199433d6423SLionel Sambuc
devman_usb_bind_cb(void * data,endpoint_t ep)200433d6423SLionel Sambuc static int devman_usb_bind_cb(void *data, endpoint_t ep) {
201433d6423SLionel Sambuc if (bind_cb) {
202433d6423SLionel Sambuc return bind_cb((struct devman_usb_bind_cb_data *) data, ep);
203433d6423SLionel Sambuc } else {
204433d6423SLionel Sambuc return ENODEV;
205433d6423SLionel Sambuc }
206433d6423SLionel Sambuc }
207433d6423SLionel Sambuc
devman_usb_unbind_cb(void * data,endpoint_t ep)208433d6423SLionel Sambuc static int devman_usb_unbind_cb(void *data, endpoint_t ep) {
209433d6423SLionel Sambuc if (unbind_cb) {
210433d6423SLionel Sambuc return unbind_cb((struct devman_usb_bind_cb_data *) data, ep);
211433d6423SLionel Sambuc } else {
212433d6423SLionel Sambuc return ENODEV;
213433d6423SLionel Sambuc }
214433d6423SLionel Sambuc }
215433d6423SLionel Sambuc
216433d6423SLionel Sambuc /****************************************************************************
217433d6423SLionel Sambuc * devman_usb_device_add *
218433d6423SLionel Sambuc ***************************************************************************/
devman_usb_device_add(struct devman_usb_dev * dev)219433d6423SLionel Sambuc int devman_usb_device_add(struct devman_usb_dev *dev)
220433d6423SLionel Sambuc {
221433d6423SLionel Sambuc int i,res = 0;
222433d6423SLionel Sambuc add_device_attributes(dev);
223433d6423SLionel Sambuc
224433d6423SLionel Sambuc /* add the USB device */
225433d6423SLionel Sambuc dev->cb_data.dev_id = dev->dev_id;
226433d6423SLionel Sambuc dev->cb_data.interface = -1;
227433d6423SLionel Sambuc
228433d6423SLionel Sambuc dev->dev->bind_cb = devman_usb_bind_cb;
229433d6423SLionel Sambuc dev->dev->unbind_cb = devman_usb_unbind_cb;
230433d6423SLionel Sambuc dev->dev->data = &dev->cb_data;
231433d6423SLionel Sambuc
232433d6423SLionel Sambuc res = devman_add_device(dev->dev);
233433d6423SLionel Sambuc
234433d6423SLionel Sambuc if (res != 0) {
235433d6423SLionel Sambuc panic("devman_usb_device_add(): devman_add_device failed.");
236433d6423SLionel Sambuc }
237433d6423SLionel Sambuc
238433d6423SLionel Sambuc /* add the USB interfaces */
239433d6423SLionel Sambuc for (i=0; i < dev->intf_count; i++) {
240433d6423SLionel Sambuc /* prepare */
241433d6423SLionel Sambuc dev->interfaces[i].dev =
242433d6423SLionel Sambuc (struct devman_dev *) malloc(sizeof(struct devman_dev));
243433d6423SLionel Sambuc CHECKOUTOFMEM(dev->interfaces[i].dev);
244433d6423SLionel Sambuc
245433d6423SLionel Sambuc TAILQ_INIT(&dev->interfaces[i].dev->attrs);
246433d6423SLionel Sambuc snprintf(dev->interfaces[i].dev->name, DEVMAN_DEV_NAME_LEN,
247433d6423SLionel Sambuc "intf%d", i);
248433d6423SLionel Sambuc
249433d6423SLionel Sambuc add_interface_attributes(&dev->interfaces[i]);
250433d6423SLionel Sambuc
251433d6423SLionel Sambuc dev->interfaces[i].dev->parent_dev_id = dev->dev->dev_id;
252433d6423SLionel Sambuc
253433d6423SLionel Sambuc
254433d6423SLionel Sambuc dev->interfaces[i].cb_data.dev_id = dev->dev_id;
255433d6423SLionel Sambuc dev->interfaces[i].cb_data.interface =
256433d6423SLionel Sambuc dev->interfaces[i].desc->bInterfaceNumber;
257433d6423SLionel Sambuc
258433d6423SLionel Sambuc dev->interfaces[i].dev->bind_cb = devman_usb_bind_cb;
259433d6423SLionel Sambuc dev->interfaces[i].dev->unbind_cb = devman_usb_unbind_cb;
260433d6423SLionel Sambuc dev->interfaces[i].dev->data = &dev->interfaces[i].cb_data;
261433d6423SLionel Sambuc
262433d6423SLionel Sambuc /* add */
263433d6423SLionel Sambuc res = devman_add_device(dev->interfaces[i].dev);
264433d6423SLionel Sambuc
265433d6423SLionel Sambuc if (res != 0) {
266433d6423SLionel Sambuc panic("devman_usb_device_add(): devman_add_device failed.");
267433d6423SLionel Sambuc }
268433d6423SLionel Sambuc }
269433d6423SLionel Sambuc
270433d6423SLionel Sambuc return res;
271433d6423SLionel Sambuc }
272433d6423SLionel Sambuc
273433d6423SLionel Sambuc /****************************************************************************
274433d6423SLionel Sambuc * devman_usb_device_remove *
275433d6423SLionel Sambuc ***************************************************************************/
devman_usb_device_remove(struct devman_usb_dev * dev)276433d6423SLionel Sambuc int devman_usb_device_remove(struct devman_usb_dev *dev)
277433d6423SLionel Sambuc {
278433d6423SLionel Sambuc int i, res = 0;
279433d6423SLionel Sambuc
280433d6423SLionel Sambuc for (i=0; i < dev->intf_count; i++) {
281433d6423SLionel Sambuc
282433d6423SLionel Sambuc res = devman_del_device(dev->interfaces[i].dev);
283433d6423SLionel Sambuc
284433d6423SLionel Sambuc if (res != 0) {
285433d6423SLionel Sambuc panic("devman_usb_device_remove(): devman_del_device failed.");
286433d6423SLionel Sambuc }
287433d6423SLionel Sambuc }
288433d6423SLionel Sambuc res = devman_del_device(dev->dev);
289433d6423SLionel Sambuc return res;
290433d6423SLionel Sambuc }
291433d6423SLionel Sambuc
292433d6423SLionel Sambuc /****************************************************************************
293433d6423SLionel Sambuc * devman_usb_init *
294433d6423SLionel Sambuc ***************************************************************************/
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))295433d6423SLionel Sambuc void devman_usb_init
296433d6423SLionel Sambuc (int (*_bind_cb) (struct devman_usb_bind_cb_data *data, endpoint_t ep),
297433d6423SLionel Sambuc int (*_unbind_cb) (struct devman_usb_bind_cb_data *data, endpoint_t ep))
298433d6423SLionel Sambuc {
299433d6423SLionel Sambuc bind_cb = _bind_cb;
300433d6423SLionel Sambuc unbind_cb = _unbind_cb;
301433d6423SLionel Sambuc }
302