1 /* $NetBSD: rumpusbhc.c,v 1.9 2009/12/15 15:50:37 pooka Exp $ */
4 * Copyright (c) 2009 Antti Kantee. All Rights Reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
30 * All rights reserved.
32 * This code is derived from software contributed to The NetBSD Foundation
33 * by Lennart Augustsson (lennart@augustsson.net) at
34 * Carlstedt Research & Technology.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
45 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
46 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
47 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
49 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
53 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55 * POSSIBILITY OF SUCH DAMAGE.
59 * This rump driver attaches ugen as a kernel usb host controller.
60 * It's still somewhat under the hammer ....
63 #include <sys/cdefs.h>
64 __KERNEL_RCSID(0, "$NetBSD: rumpusbhc.c,v 1.9 2009/12/15 15:50:37 pooka Exp $");
66 #include <sys/param.h>
69 #include <sys/device.h>
70 #include <sys/fcntl.h>
72 #include <sys/kernel.h>
73 #include <sys/kthread.h>
75 #include <dev/usb/usb.h>
76 #include <dev/usb/usbdi.h>
77 #include <dev/usb/usbdivar.h>
78 #include <dev/usb/usb_mem.h>
79 #include <dev/usb/usbroothub_subr.h>
81 #include <rump/rumpuser.h>
83 #include "rump_private.h"
84 #include "rump_dev_private.h"
87 #define UGEN_EPT_CTRL 0 /* ugenx.00 is the control endpoint */
89 struct rumpusbhc_softc
{
90 struct usbd_bus sc_bus
;
93 int sc_ugenfd
[UGEN_NEPTS
];
94 int sc_fdmodes
[UGEN_NEPTS
];
102 static const struct cfiattrdata usb_iattrdata
= {
107 static const struct cfiattrdata
*const rumpusbhc_attrs
[] = {
112 static int rumpusbhc_probe(struct device
*, struct cfdata
*, void *);
113 static void rumpusbhc_attach(struct device
*, struct device
*, void *);
115 CFATTACH_DECL_NEW(rumpusbhc
, sizeof(struct rumpusbhc_softc
),
116 rumpusbhc_probe
, rumpusbhc_attach
, NULL
, NULL
);
117 CFDRIVER_DECL(rumpusbhc
, DV_DULL
, rumpusbhc_attrs
);
119 struct cfparent rumpusbhcpar
= {
126 struct usbd_xfer rusb_xfer
;
127 int rusb_status
; /* now this is a cheap trick */
129 #define RUSB(x) ((struct rusb_xfer *)x)
131 /* probe ugen0 through ugen3 */
132 struct cfdata rumpusbhc_cfdata
[] = {
133 { "rumpusbhc", "rumpusbhc", 0, FSTATE_NOTFOUND
, NULL
, 0, &rumpusbhcpar
},
134 { "rumpusbhc", "rumpusbhc", 1, FSTATE_NOTFOUND
, NULL
, 0, &rumpusbhcpar
},
135 { "rumpusbhc", "rumpusbhc", 2, FSTATE_NOTFOUND
, NULL
, 0, &rumpusbhcpar
},
136 { "rumpusbhc", "rumpusbhc", 3, FSTATE_NOTFOUND
, NULL
, 0, &rumpusbhcpar
},
139 #define UGENDEV_BASESTR "/dev/ugen"
140 #define UGENDEV_BUFSIZE 32
142 makeugendevstr(int devnum
, int endpoint
, char *buf
)
145 CTASSERT(UGENDEV_BUFSIZE
> sizeof(UGENDEV_BASESTR
)+sizeof("0.00")+1);
146 sprintf(buf
, "%s%d.%02d", UGENDEV_BASESTR
, devnum
, endpoint
);
150 * Our fictional hubbie.
153 static const usb_device_descriptor_t rumphub_udd
= {
154 .bLength
= USB_DEVICE_DESCRIPTOR_SIZE
,
155 .bDescriptorType
= UDESC_DEVICE
,
156 .bDeviceClass
= UDCLASS_HUB
,
157 .bDeviceSubClass
= UDSUBCLASS_HUB
,
158 .bDeviceProtocol
= UDPROTO_FSHUB
,
159 .bMaxPacketSize
= 64,
160 .bNumConfigurations
= 1,
163 static const usb_config_descriptor_t rumphub_ucd
= {
164 .bLength
= USB_CONFIG_DESCRIPTOR_SIZE
,
165 .bDescriptorType
= UDESC_CONFIG
,
166 .wTotalLength
= { USB_CONFIG_DESCRIPTOR_SIZE
167 + USB_INTERFACE_DESCRIPTOR_SIZE
168 + USB_ENDPOINT_DESCRIPTOR_SIZE
},
170 .bmAttributes
= UC_SELF_POWERED
| UC_ATTR_MBO
,
172 /* XXX: spec says UC_ATTR_MBO is reserved and set to one. required? */
174 static const usb_interface_descriptor_t rumphub_uid
= {
175 .bLength
= USB_INTERFACE_DESCRIPTOR_SIZE
,
176 .bDescriptorType
= UDESC_INTERFACE
,
177 .bInterfaceNumber
= 0,
179 .bInterfaceClass
= UICLASS_HUB
,
180 .bInterfaceSubClass
= UISUBCLASS_HUB
,
181 .bInterfaceProtocol
= UIPROTO_FSHUB
,
184 static const usb_endpoint_descriptor_t rumphub_epd
= {
185 .bLength
= USB_ENDPOINT_DESCRIPTOR_SIZE
,
186 .bDescriptorType
= UDESC_ENDPOINT
,
187 .bmAttributes
= UE_INTERRUPT
,
188 .wMaxPacketSize
= {64, 0},
191 static const usb_hub_descriptor_t rumphub_hdd
= {
192 .bDescLength
= USB_HUB_DESCRIPTOR_SIZE
,
193 .bDescriptorType
= UDESC_HUB
,
198 rumpusb_root_ctrl_start(usbd_xfer_handle xfer
)
200 usb_device_request_t
*req
= &xfer
->request
;
201 struct rumpusbhc_softc
*sc
= xfer
->pipe
->device
->bus
->hci_private
;
202 int len
, totlen
, value
, curlen
, err
;
205 len
= totlen
= UGETW(req
->wLength
);
207 buf
= KERNADDR(&xfer
->dmabuf
, 0);
208 value
= UGETW(req
->wValue
);
210 #define C(x,y) ((x) | ((y) << 8))
211 switch(C(req
->bRequest
, req
->bmRequestType
)) {
213 case C(UR_GET_CONFIG
, UT_READ_DEVICE
):
220 case C(UR_GET_DESCRIPTOR
, UT_READ_DEVICE
):
221 switch (value
>> 8) {
223 totlen
= min(len
, USB_DEVICE_DESCRIPTOR_SIZE
);
224 memcpy(buf
, &rumphub_udd
, totlen
);
229 curlen
= min(len
, USB_CONFIG_DESCRIPTOR_SIZE
);
230 memcpy(buf
, &rumphub_ucd
, curlen
);
235 curlen
= min(len
, USB_INTERFACE_DESCRIPTOR_SIZE
);
236 memcpy(buf
, &rumphub_uid
, curlen
);
241 curlen
= min(len
, USB_ENDPOINT_DESCRIPTOR_SIZE
);
242 memcpy(buf
, &rumphub_epd
, curlen
);
249 #define sd ((usb_string_descriptor_t *)buf)
250 switch (value
& 0xff) {
251 case 0: /* Language table */
252 totlen
= usb_makelangtbl(sd
, len
);
255 totlen
= usb_makestrdesc(sd
, len
, "rod nevada");
257 case 2: /* Product */
258 totlen
= usb_makestrdesc(sd
, len
,
259 "RUMPUSBHC root hub");
266 panic("unhandled read device request");
271 case C(UR_SET_ADDRESS
, UT_WRITE_DEVICE
):
272 if (value
>= USB_MAX_DEVICES
) {
279 case C(UR_SET_CONFIG
, UT_WRITE_DEVICE
):
280 if (value
!= 0 && value
!= 1) {
287 case C(UR_SET_FEATURE
, UT_WRITE_CLASS_OTHER
):
290 sc
->sc_port_change
|= UPS_C_PORT_RESET
;
299 case C(UR_CLEAR_FEATURE
, UT_WRITE_CLASS_OTHER
):
300 sc
->sc_port_change
&= ~value
;
303 case C(UR_GET_DESCRIPTOR
, UT_READ_CLASS_DEVICE
):
304 totlen
= min(len
, USB_HUB_DESCRIPTOR_SIZE
);
305 memcpy(buf
, &rumphub_hdd
, totlen
);
308 case C(UR_GET_STATUS
, UT_READ_CLASS_DEVICE
):
309 /* huh? other hc's do this */
314 case C(UR_GET_STATUS
, UT_READ_CLASS_OTHER
):
316 usb_port_status_t ps
;
318 USETW(ps
.wPortStatus
, sc
->sc_port_status
);
319 USETW(ps
.wPortChange
, sc
->sc_port_change
);
320 totlen
= min(len
, sizeof(ps
));
321 memcpy(buf
, &ps
, totlen
);
326 panic("unhandled request");
329 err
= USBD_NORMAL_COMPLETION
;
330 xfer
->actlen
= totlen
;
334 usb_transfer_complete(xfer
);
335 return (USBD_IN_PROGRESS
);
339 rumpusb_root_ctrl_transfer(usbd_xfer_handle xfer
)
343 err
= usb_insert_transfer(xfer
);
347 return (rumpusb_root_ctrl_start(SIMPLEQ_FIRST(&xfer
->pipe
->queue
)));
351 rumpusb_root_ctrl_abort(usbd_xfer_handle xfer
)
357 rumpusb_root_ctrl_close(usbd_pipe_handle pipe
)
363 rumpusb_root_ctrl_cleartoggle(usbd_pipe_handle pipe
)
369 rumpusb_root_ctrl_done(usbd_xfer_handle xfer
)
374 static const struct usbd_pipe_methods rumpusb_root_ctrl_methods
= {
375 .transfer
= rumpusb_root_ctrl_transfer
,
376 .start
= rumpusb_root_ctrl_start
,
377 .abort
= rumpusb_root_ctrl_abort
,
378 .close
= rumpusb_root_ctrl_close
,
379 .cleartoggle
= rumpusb_root_ctrl_cleartoggle
,
380 .done
= rumpusb_root_ctrl_done
,
384 rumpusb_device_ctrl_start(usbd_xfer_handle xfer
)
386 usb_device_request_t
*req
= &xfer
->request
;
387 struct rumpusbhc_softc
*sc
= xfer
->pipe
->device
->bus
->hci_private
;
394 len
= totlen
= UGETW(req
->wLength
);
396 buf
= KERNADDR(&xfer
->dmabuf
, 0);
397 value
= UGETW(req
->wValue
);
399 #define C(x,y) ((x) | ((y) << 8))
400 switch(C(req
->bRequest
, req
->bmRequestType
)) {
401 case C(UR_GET_DESCRIPTOR
, UT_READ_DEVICE
):
405 usb_device_descriptor_t uddesc
;
406 totlen
= min(len
, USB_DEVICE_DESCRIPTOR_SIZE
);
407 memset(buf
, 0, totlen
);
408 if (rumpuser_ioctl(sc
->sc_ugenfd
[UGEN_EPT_CTRL
],
409 USB_GET_DEVICE_DESC
, &uddesc
, &ru_error
) == -1)
410 panic("%d", ru_error
);
411 memcpy(buf
, &uddesc
, totlen
);
417 struct usb_full_desc ufdesc
;
418 ufdesc
.ufd_config_index
= 0;
419 ufdesc
.ufd_size
= len
;
420 ufdesc
.ufd_data
= buf
;
421 memset(buf
, 0, totlen
);
422 if (rumpuser_ioctl(sc
->sc_ugenfd
[UGEN_EPT_CTRL
],
423 USB_GET_FULL_DESC
, &ufdesc
, &ru_error
) == -1)
424 panic("%d", ru_error
);
431 struct usb_device_info udi
;
433 if (rumpuser_ioctl(sc
->sc_ugenfd
[UGEN_EPT_CTRL
],
434 USB_GET_DEVICEINFO
, &udi
, &ru_error
) == -1) {
435 printf("rumpusbhc: get dev info failed: %d\n",
441 switch (value
& 0xff) {
442 #define sd ((usb_string_descriptor_t *)buf)
443 case 0: /* language table */
446 totlen
= usb_makestrdesc(sd
, len
,
449 case 2: /* product */
450 totlen
= usb_makestrdesc(sd
, len
,
459 panic("not handled");
463 case C(UR_SET_ADDRESS
, UT_WRITE_DEVICE
):
464 /* ignored, ugen won't let us */
467 case C(UR_SET_CONFIG
, UT_WRITE_DEVICE
):
468 /* ignored, ugen won't let us .... REALLY? */
471 case C(UR_SET_INTERFACE
, UT_WRITE_INTERFACE
):
473 struct usb_alt_interface uai
;
476 uai
.uai_interface_index
= UGETW(req
->wIndex
);
477 uai
.uai_alt_no
= value
;
478 if (rumpuser_ioctl(sc
->sc_ugenfd
[UGEN_EPT_CTRL
],
479 USB_SET_ALTINTERFACE
, &uai
, &ru_error
) == -1) {
480 printf("rumpusbhc: set alt interface failed: %d\n",
489 * XXX: don't wildcard these yet. I want to better figure
490 * out what to trap here. This is kinda silly, though ...
492 case C(0x01, UT_WRITE_VENDOR_DEVICE
):
493 case C(0x06, UT_WRITE_VENDOR_DEVICE
):
494 case C(0x07, UT_READ_VENDOR_DEVICE
):
495 case C(0x09, UT_READ_VENDOR_DEVICE
):
496 case C(0xfe, UT_READ_CLASS_INTERFACE
):
497 case C(0x01, UT_READ_CLASS_INTERFACE
):
498 case C(UR_GET_STATUS
, UT_READ_CLASS_OTHER
):
499 case C(UR_GET_STATUS
, UT_READ_CLASS_DEVICE
):
500 case C(UR_GET_DESCRIPTOR
, UT_READ_CLASS_DEVICE
):
501 case C(0xff, UT_WRITE_CLASS_INTERFACE
):
502 case C(0x20, UT_WRITE_CLASS_INTERFACE
):
503 case C(0x22, UT_WRITE_CLASS_INTERFACE
):
504 case C(UR_SET_FEATURE
, UT_WRITE_CLASS_OTHER
):
505 case C(UR_CLEAR_FEATURE
, UT_WRITE_CLASS_OTHER
):
506 case C(UR_CLEAR_FEATURE
, UT_WRITE_ENDPOINT
):
508 struct usb_ctl_request ucr
;
510 memcpy(&ucr
.ucr_request
, req
, sizeof(ucr
.ucr_request
));
512 if (rumpuser_ioctl(sc
->sc_ugenfd
[UGEN_EPT_CTRL
],
513 USB_DO_REQUEST
, &ucr
, &ru_error
) == -1) {
514 panic("request failed");
520 panic("unhandled request");
523 xfer
->actlen
= totlen
;
524 err
= USBD_NORMAL_COMPLETION
;
528 usb_transfer_complete(xfer
);
529 return (USBD_IN_PROGRESS
);
533 rumpusb_device_ctrl_transfer(usbd_xfer_handle xfer
)
537 err
= usb_insert_transfer(xfer
);
541 return (rumpusb_device_ctrl_start(SIMPLEQ_FIRST(&xfer
->pipe
->queue
)));
545 rumpusb_device_ctrl_abort(usbd_xfer_handle xfer
)
551 rumpusb_device_ctrl_close(usbd_pipe_handle pipe
)
557 rumpusb_device_ctrl_cleartoggle(usbd_pipe_handle pipe
)
563 rumpusb_device_ctrl_done(usbd_xfer_handle xfer
)
568 static const struct usbd_pipe_methods rumpusb_device_ctrl_methods
= {
569 .transfer
= rumpusb_device_ctrl_transfer
,
570 .start
= rumpusb_device_ctrl_start
,
571 .abort
= rumpusb_device_ctrl_abort
,
572 .close
= rumpusb_device_ctrl_close
,
573 .cleartoggle
= rumpusb_device_ctrl_cleartoggle
,
574 .done
= rumpusb_device_ctrl_done
,
578 usbd_xfer_handle xfer
;
579 LIST_ENTRY(intrent
) entries
;
582 static LIST_HEAD(, intrent
) intrlist
= LIST_HEAD_INITIALIZER(intrlist
);
587 struct intrent
*ie
, *ie_next
;
588 usbd_xfer_handle xfer
;
590 for (ie
= LIST_FIRST(&intrlist
); ie
; ie
= ie_next
) {
592 xfer
->actlen
= xfer
->length
;
593 xfer
->status
= USBD_NORMAL_COMPLETION
;
594 usb_transfer_complete(xfer
);
596 ie_next
= LIST_NEXT(ie
, entries
);
597 LIST_REMOVE(ie
, entries
);
598 kmem_free(ie
, sizeof(*ie
));
603 rumpusb_root_intr_start(usbd_xfer_handle xfer
)
607 ie
= kmem_alloc(sizeof(*ie
), KM_SLEEP
);
609 LIST_INSERT_HEAD(&intrlist
, ie
, entries
);
611 return (USBD_IN_PROGRESS
);
615 rumpusb_root_intr_transfer(usbd_xfer_handle xfer
)
619 err
= usb_insert_transfer(xfer
);
623 return (rumpusb_root_intr_start(SIMPLEQ_FIRST(&xfer
->pipe
->queue
)));
627 rumpusb_root_intr_abort(usbd_xfer_handle xfer
)
633 rumpusb_root_intr_close(usbd_pipe_handle pipe
)
639 rumpusb_root_intr_cleartoggle(usbd_pipe_handle pipe
)
645 rumpusb_root_intr_done(usbd_xfer_handle xfer
)
650 static const struct usbd_pipe_methods rumpusb_root_intr_methods
= {
651 .transfer
= rumpusb_root_intr_transfer
,
652 .start
= rumpusb_root_intr_start
,
653 .abort
= rumpusb_root_intr_abort
,
654 .close
= rumpusb_root_intr_close
,
655 .cleartoggle
= rumpusb_root_intr_cleartoggle
,
656 .done
= rumpusb_root_intr_done
,
660 rumpusb_device_bulk_start(usbd_xfer_handle xfer
)
662 struct rumpusbhc_softc
*sc
= xfer
->pipe
->device
->bus
->hci_private
;
666 int len
, error
, endpt
;
671 endpt
= xfer
->pipe
->endpoint
->edesc
->bEndpointAddress
;
672 isread
= UE_GET_DIR(endpt
) == UE_DIR_IN
;
673 endpt
= UE_GET_ADDR(endpt
);
674 KASSERT(endpt
< UGEN_NEPTS
);
676 KASSERT(xfer
->length
);
678 buf
= KERNADDR(&xfer
->dmabuf
, 0);
681 while (RUSB(xfer
)->rusb_status
== 0) {
683 if (xfer
->flags
& USBD_SHORT_XFER_OK
)
687 rumpuser_ioctl(sc
->sc_ugenfd
[endpt
],
688 USB_SET_SHORT_XFER
, &val
, &error
);
689 n
= rumpuser_read(sc
->sc_ugenfd
[endpt
],
690 buf
+done
, len
-done
, &error
);
692 if (error
== ETIMEDOUT
)
695 xfer
->status
= USBD_IOERROR
;
702 n
= rumpuser_write(sc
->sc_ugenfd
[endpt
],
708 panic("short write");
711 if (xfer
->flags
& USBD_SHORT_XFER_OK
)
715 if (RUSB(xfer
)->rusb_status
== 0) {
717 xfer
->status
= USBD_NORMAL_COMPLETION
;
721 xfer
->status
= xfererr
;
724 xfer
->status
= USBD_CANCELLED
;
725 RUSB(xfer
)->rusb_status
= 2;
729 rumpuser_ioctl(sc
->sc_ugenfd
[endpt
], USB_SET_SHORT_XFER
, &val
, &error
);
730 usb_transfer_complete(xfer
);
731 return (USBD_IN_PROGRESS
);
735 doxfer_kth(void *arg
)
737 usbd_xfer_handle xfer
= arg
;
739 rumpusb_device_bulk_start(SIMPLEQ_FIRST(&xfer
->pipe
->queue
));
744 rumpusb_device_bulk_transfer(usbd_xfer_handle xfer
)
749 /* XXX: lie about supporting async transfers */
750 if ((xfer
->flags
& USBD_SYNCHRONOUS
) == 0) {
751 printf("non-threaded rump does not support "
752 "async transfers.\n");
753 return USBD_IN_PROGRESS
;
756 err
= usb_insert_transfer(xfer
);
760 return rumpusb_device_bulk_start(
761 SIMPLEQ_FIRST(&xfer
->pipe
->queue
));
764 err
= usb_insert_transfer(xfer
);
767 kthread_create(PRI_NONE
, 0, NULL
, doxfer_kth
, xfer
, NULL
,
770 return USBD_IN_PROGRESS
;
774 /* wait for transfer to abort. yea, this is cheesy (from a spray can) */
776 rumpusb_device_bulk_abort(usbd_xfer_handle xfer
)
778 struct rusb_xfer
*rx
= RUSB(xfer
);
781 while (rx
->rusb_status
< 2) {
782 kpause("jopo", false, hz
/10, NULL
);
787 rumpusb_device_bulk_close(usbd_pipe_handle pipe
)
793 rumpusb_device_bulk_cleartoggle(usbd_pipe_handle pipe
)
799 rumpusb_device_bulk_done(usbd_xfer_handle xfer
)
804 static const struct usbd_pipe_methods rumpusb_device_bulk_methods
= {
805 .transfer
= rumpusb_device_bulk_transfer
,
806 .start
= rumpusb_device_bulk_start
,
807 .abort
= rumpusb_device_bulk_abort
,
808 .close
= rumpusb_device_bulk_close
,
809 .cleartoggle
= rumpusb_device_bulk_cleartoggle
,
810 .done
= rumpusb_device_bulk_done
,
813 static const struct usbd_pipe_methods rumpusb_device_intr_methods
= {
814 .transfer
= rumpusb_root_intr_transfer
,
815 .start
= rumpusb_root_intr_start
,
816 .abort
= rumpusb_root_intr_abort
,
817 .close
= rumpusb_root_intr_close
,
818 .cleartoggle
= rumpusb_root_intr_cleartoggle
,
819 .done
= rumpusb_root_intr_done
,
823 rumpusbhc_open(struct usbd_pipe
*pipe
)
825 usbd_device_handle dev
= pipe
->device
;
826 struct rumpusbhc_softc
*sc
= dev
->bus
->hci_private
;
827 usb_endpoint_descriptor_t
*ed
= pipe
->endpoint
->edesc
;
828 u_int8_t addr
= dev
->address
;
829 u_int8_t xfertype
= ed
->bmAttributes
& UE_XFERTYPE
;
830 char buf
[UGENDEV_BUFSIZE
];
831 int endpt
, oflags
, error
;
834 sc
->sc_port_status
= UPS_CURRENT_CONNECT_STATUS
835 | UPS_PORT_ENABLED
| UPS_PORT_POWER
;
836 sc
->sc_port_change
= UPS_C_CONNECT_STATUS
;
838 if (addr
== sc
->sc_addr
) {
841 pipe
->methods
= &rumpusb_root_ctrl_methods
;
844 pipe
->methods
= &rumpusb_root_intr_methods
;
847 panic("%d not supported", xfertype
);
853 pipe
->methods
= &rumpusb_device_ctrl_methods
;
857 endpt
= pipe
->endpoint
->edesc
->bEndpointAddress
;
858 if (UE_GET_DIR(endpt
) == UE_DIR_IN
) {
863 endpt
= UE_GET_ADDR(endpt
);
864 pipe
->methods
= &rumpusb_device_bulk_methods
;
866 if (sc
->sc_fdmodes
[endpt
] == oflags
867 || sc
->sc_fdmodes
[endpt
] == O_RDWR
)
870 if (sc
->sc_fdmodes
[endpt
] != -1) {
871 /* XXX: closing from under someone? */
872 rumpuser_close(sc
->sc_ugenfd
[endpt
], &error
);
876 makeugendevstr(sc
->sc_devnum
, endpt
, buf
);
877 fd
= rumpuser_open(buf
, oflags
, &error
);
879 return USBD_INVAL
; /* XXX: no mapping */
881 if (rumpuser_ioctl(fd
, USB_SET_TIMEOUT
, &val
,
883 panic("timeout set failed");
884 sc
->sc_ugenfd
[endpt
] = fd
;
885 sc
->sc_fdmodes
[endpt
] = oflags
;
888 panic("%d not supported", xfertype
);
897 rumpusbhc_softint(void *arg
)
903 rumpusbhc_poll(struct usbd_bus
*ubus
)
909 rumpusbhc_allocm(struct usbd_bus
*bus
, usb_dma_t
*dma
, uint32_t size
)
911 struct rumpusbhc_softc
*sc
= bus
->hci_private
;
913 return usb_allocmem(&sc
->sc_bus
, size
, 0, dma
);
917 rumpusbhc_freem(struct usbd_bus
*ubus
, usb_dma_t
*udma
)
922 static struct usbd_xfer
*
923 rumpusbhc_allocx(struct usbd_bus
*bus
)
925 usbd_xfer_handle xfer
;
927 xfer
= kmem_zalloc(sizeof(struct usbd_xfer
), KM_SLEEP
);
928 xfer
->busy_free
= XFER_BUSY
;
934 rumpusbhc_freex(struct usbd_bus
*bus
, struct usbd_xfer
*xfer
)
937 kmem_free(xfer
, sizeof(struct usbd_xfer
));
940 struct rumpusbhc_pipe
{
941 struct usbd_pipe pipe
;
944 static const struct usbd_bus_methods rumpusbhc_bus_methods
= {
945 .open_pipe
= rumpusbhc_open
,
946 .soft_intr
= rumpusbhc_softint
,
947 .do_poll
= rumpusbhc_poll
,
948 .allocm
= rumpusbhc_allocm
,
949 .freem
= rumpusbhc_freem
,
950 .allocx
= rumpusbhc_allocx
,
951 .freex
= rumpusbhc_freex
,
955 rump_dev_rumpusbhc_init()
959 error
= config_cfdriver_attach(&rumpusbhc_cd
);
961 panic("rumpusbhc cfdriver attach failed: %d", error
);
962 error
= config_cfattach_attach("rumpusbhc", &rumpusbhc_ca
);
964 panic("rumpusbhc cfattach attach failed: %d", error
);
965 error
= config_cfdata_attach(rumpusbhc_cfdata
, 0);
967 panic("rumpusbhc cfdata attach failed: %d", error
);
971 rumpusbhc_probe(struct device
*parent
, struct cfdata
*match
, void *aux
)
973 char buf
[UGENDEV_BUFSIZE
];
976 makeugendevstr(match
->cf_unit
, 0, buf
);
977 fd
= rumpuser_open(buf
, O_RDWR
, &error
);
981 rumpuser_close(fd
, &error
);
986 rumpusbhc_attach(struct device
*parent
, struct device
*self
, void *aux
)
988 struct mainbus_attach_args
*maa
= aux
;
989 struct rumpusbhc_softc
*sc
= device_private(self
);
990 char buf
[UGENDEV_BUFSIZE
];
995 memset(sc
, 0, sizeof(*sc
));
996 memset(&sc
->sc_ugenfd
, -1, sizeof(sc
->sc_ugenfd
));
997 memset(&sc
->sc_fdmodes
, -1, sizeof(sc
->sc_fdmodes
));
999 sc
->sc_bus
.usbrev
= USBREV_2_0
;
1000 sc
->sc_bus
.methods
= &rumpusbhc_bus_methods
;
1001 sc
->sc_bus
.hci_private
= sc
;
1002 sc
->sc_bus
.pipe_size
= sizeof(struct rumpusbhc_pipe
);
1003 sc
->sc_devnum
= maa
->maa_unit
;
1005 makeugendevstr(sc
->sc_devnum
, 0, buf
);
1006 sc
->sc_ugenfd
[UGEN_EPT_CTRL
] = rumpuser_open(buf
, O_RDWR
, &error
);
1008 panic("rumpusbhc_attach: failed to open ctrl ept %s\n", buf
);
1010 config_found(self
, &sc
->sc_bus
, usbctlprint
);
1012 /* whoah, like extreme XXX, bro */
1015 config_pending_decr();