| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: vhci.c,v 1.11 2020/03/24 07:11:07 maxv Exp $ */ | | 1 | /* $NetBSD: vhci.c,v 1.12 2020/03/24 17:20:55 maxv Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2019-2020 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2019-2020 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Maxime Villard. | | 8 | * by Maxime Villard. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -20,27 +20,27 @@ | | | @@ -20,27 +20,27 @@ |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: vhci.c,v 1.11 2020/03/24 07:11:07 maxv Exp $"); | | 33 | __KERNEL_RCSID(0, "$NetBSD: vhci.c,v 1.12 2020/03/24 17:20:55 maxv Exp $"); |
34 | | | 34 | |
35 | #ifdef _KERNEL_OPT | | 35 | #ifdef _KERNEL_OPT |
36 | #include "opt_usb.h" | | 36 | #include "opt_usb.h" |
37 | #endif | | 37 | #endif |
38 | | | 38 | |
39 | #include <sys/param.h> | | 39 | #include <sys/param.h> |
40 | | | 40 | |
41 | #include <sys/bus.h> | | 41 | #include <sys/bus.h> |
42 | #include <sys/cpu.h> | | 42 | #include <sys/cpu.h> |
43 | #include <sys/conf.h> | | 43 | #include <sys/conf.h> |
44 | #include <sys/device.h> | | 44 | #include <sys/device.h> |
45 | #include <sys/kernel.h> | | 45 | #include <sys/kernel.h> |
46 | #include <sys/kmem.h> | | 46 | #include <sys/kmem.h> |
| @@ -794,72 +794,62 @@ struct vhci_ioc_get_info { | | | @@ -794,72 +794,62 @@ struct vhci_ioc_get_info { |
794 | | | 794 | |
795 | /* Current addr. */ | | 795 | /* Current addr. */ |
796 | uint8_t addr; | | 796 | uint8_t addr; |
797 | }; | | 797 | }; |
798 | | | 798 | |
799 | struct vhci_ioc_set_port { | | 799 | struct vhci_ioc_set_port { |
800 | u_int port; | | 800 | u_int port; |
801 | }; | | 801 | }; |
802 | | | 802 | |
803 | struct vhci_ioc_set_addr { | | 803 | struct vhci_ioc_set_addr { |
804 | uint8_t addr; | | 804 | uint8_t addr; |
805 | }; | | 805 | }; |
806 | | | 806 | |
807 | struct vhci_ioc_usb_attach { | | | |
808 | u_int port; | | | |
809 | }; | | | |
810 | | | | |
811 | struct vhci_ioc_usb_detach { | | | |
812 | u_int port; | | | |
813 | }; | | | |
814 | | | | |
815 | #define VHCI_IOC_GET_INFO _IOR('V', 0, struct vhci_ioc_get_info) | | 807 | #define VHCI_IOC_GET_INFO _IOR('V', 0, struct vhci_ioc_get_info) |
816 | #define VHCI_IOC_SET_PORT _IOW('V', 1, struct vhci_ioc_set_port) | | 808 | #define VHCI_IOC_SET_PORT _IOW('V', 1, struct vhci_ioc_set_port) |
817 | #define VHCI_IOC_SET_ADDR _IOW('V', 2, struct vhci_ioc_set_addr) | | 809 | #define VHCI_IOC_SET_ADDR _IOW('V', 2, struct vhci_ioc_set_addr) |
818 | #define VHCI_IOC_USB_ATTACH _IOW('V', 10, struct vhci_ioc_usb_attach) | | 810 | #define VHCI_IOC_USB_ATTACH _IO ('V', 10) |
819 | #define VHCI_IOC_USB_DETACH _IOW('V', 11, struct vhci_ioc_usb_detach) | | 811 | #define VHCI_IOC_USB_DETACH _IO ('V', 11) |
820 | | | 812 | |
821 | static int | | 813 | static int |
822 | vhci_usb_attach(vhci_fd_t *vfd, struct vhci_ioc_usb_attach *args) | | 814 | vhci_usb_attach(vhci_fd_t *vfd) |
823 | { | | 815 | { |
824 | vhci_softc_t *sc = vfd->softc; | | 816 | vhci_softc_t *sc = vfd->softc; |
825 | vhci_port_t *port; | | 817 | vhci_port_t *port; |
826 | struct usbd_xfer *xfer; | | 818 | struct usbd_xfer *xfer; |
827 | u_char *p; | | 819 | u_char *p; |
828 | int ret = 0; | | 820 | int ret = 0; |
829 | | | 821 | |
830 | if (args->port == 0 || args->port >= sc->sc_nports) | | 822 | port = &sc->sc_port[vfd->port]; |
831 | return EINVAL; | | | |
832 | port = &sc->sc_port[args->port]; | | | |
833 | | | 823 | |
834 | mutex_enter(&sc->sc_lock); | | 824 | mutex_enter(&sc->sc_lock); |
835 | | | 825 | |
836 | mutex_enter(&port->lock); | | 826 | mutex_enter(&port->lock); |
837 | port->status = UPS_CURRENT_CONNECT_STATUS | UPS_PORT_ENABLED | | | 827 | port->status = UPS_CURRENT_CONNECT_STATUS | UPS_PORT_ENABLED | |
838 | UPS_PORT_POWER; | | 828 | UPS_PORT_POWER; |
839 | port->change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET; | | 829 | port->change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET; |
840 | mutex_exit(&port->lock); | | 830 | mutex_exit(&port->lock); |
841 | | | 831 | |
842 | xfer = sc->sc_intrxfer; | | 832 | xfer = sc->sc_intrxfer; |
843 | | | 833 | |
844 | if (xfer == NULL) { | | 834 | if (xfer == NULL) { |
845 | ret = ENOBUFS; | | 835 | ret = ENOBUFS; |
846 | goto done; | | 836 | goto done; |
847 | } | | 837 | } |
848 | KASSERT(xfer->ux_status == USBD_IN_PROGRESS); | | 838 | KASSERT(xfer->ux_status == USBD_IN_PROGRESS); |
849 | | | 839 | |
850 | p = xfer->ux_buf; | | 840 | p = xfer->ux_buf; |
851 | memset(p, 0, xfer->ux_length); | | 841 | memset(p, 0, xfer->ux_length); |
852 | p[0] = __BIT(args->port); | | 842 | p[0] = __BIT(vfd->port); |
853 | xfer->ux_actlen = xfer->ux_length; | | 843 | xfer->ux_actlen = xfer->ux_length; |
854 | xfer->ux_status = USBD_NORMAL_COMPLETION; | | 844 | xfer->ux_status = USBD_NORMAL_COMPLETION; |
855 | | | 845 | |
856 | usb_transfer_complete(xfer); | | 846 | usb_transfer_complete(xfer); |
857 | | | 847 | |
858 | done: | | 848 | done: |
859 | mutex_exit(&sc->sc_lock); | | 849 | mutex_exit(&sc->sc_lock); |
860 | return ret; | | 850 | return ret; |
861 | } | | 851 | } |
862 | | | 852 | |
863 | static void | | 853 | static void |
864 | vhci_port_flush(vhci_softc_t *sc, vhci_port_t *port) | | 854 | vhci_port_flush(vhci_softc_t *sc, vhci_port_t *port) |
865 | { | | 855 | { |
| @@ -899,54 +889,52 @@ vhci_port_flush(vhci_softc_t *sc, vhci_p | | | @@ -899,54 +889,52 @@ vhci_port_flush(vhci_softc_t *sc, vhci_p |
899 | | | 889 | |
900 | /* Terminate all the xfers collected. */ | | 890 | /* Terminate all the xfers collected. */ |
901 | while ((vxfer = TAILQ_FIRST(&vxferlist)) != NULL) { | | 891 | while ((vxfer = TAILQ_FIRST(&vxferlist)) != NULL) { |
902 | struct usbd_xfer *xfer = &vxfer->xfer; | | 892 | struct usbd_xfer *xfer = &vxfer->xfer; |
903 | TAILQ_REMOVE(&vxferlist, vxfer, freelist); | | 893 | TAILQ_REMOVE(&vxferlist, vxfer, freelist); |
904 | | | 894 | |
905 | xfer->ux_status = USBD_TIMEOUT; | | 895 | xfer->ux_status = USBD_TIMEOUT; |
906 | usb_transfer_complete(xfer); | | 896 | usb_transfer_complete(xfer); |
907 | } | | 897 | } |
908 | } | | 898 | } |
909 | } | | 899 | } |
910 | | | 900 | |
911 | static int | | 901 | static int |
912 | vhci_usb_detach(vhci_fd_t *vfd, struct vhci_ioc_usb_detach *args) | | 902 | vhci_usb_detach(vhci_fd_t *vfd) |
913 | { | | 903 | { |
914 | vhci_softc_t *sc = vfd->softc; | | 904 | vhci_softc_t *sc = vfd->softc; |
915 | vhci_port_t *port; | | 905 | vhci_port_t *port; |
916 | struct usbd_xfer *xfer; | | 906 | struct usbd_xfer *xfer; |
917 | u_char *p; | | 907 | u_char *p; |
918 | | | 908 | |
919 | if (args->port == 0 || args->port >= sc->sc_nports) | | 909 | port = &sc->sc_port[vfd->port]; |
920 | return EINVAL; | | | |
921 | port = &sc->sc_port[args->port]; | | | |
922 | | | 910 | |
923 | mutex_enter(&sc->sc_lock); | | 911 | mutex_enter(&sc->sc_lock); |
924 | | | 912 | |
925 | xfer = sc->sc_intrxfer; | | 913 | xfer = sc->sc_intrxfer; |
926 | if (xfer == NULL) { | | 914 | if (xfer == NULL) { |
927 | mutex_exit(&sc->sc_lock); | | 915 | mutex_exit(&sc->sc_lock); |
928 | return ENOBUFS; | | 916 | return ENOBUFS; |
929 | } | | 917 | } |
930 | KASSERT(xfer->ux_status == USBD_IN_PROGRESS); | | 918 | KASSERT(xfer->ux_status == USBD_IN_PROGRESS); |
931 | | | 919 | |
932 | mutex_enter(&port->lock); | | 920 | mutex_enter(&port->lock); |
933 | | | 921 | |
934 | port->status = 0; | | 922 | port->status = 0; |
935 | port->change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET; | | 923 | port->change = UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET; |
936 | | | 924 | |
937 | p = xfer->ux_buf; | | 925 | p = xfer->ux_buf; |
938 | memset(p, 0, xfer->ux_length); | | 926 | memset(p, 0, xfer->ux_length); |
939 | p[0] = __BIT(args->port); | | 927 | p[0] = __BIT(vfd->port); |
940 | xfer->ux_actlen = xfer->ux_length; | | 928 | xfer->ux_actlen = xfer->ux_length; |
941 | xfer->ux_status = USBD_NORMAL_COMPLETION; | | 929 | xfer->ux_status = USBD_NORMAL_COMPLETION; |
942 | | | 930 | |
943 | usb_transfer_complete(xfer); | | 931 | usb_transfer_complete(xfer); |
944 | vhci_port_flush(sc, port); | | 932 | vhci_port_flush(sc, port); |
945 | | | 933 | |
946 | mutex_exit(&port->lock); | | 934 | mutex_exit(&port->lock); |
947 | mutex_exit(&sc->sc_lock); | | 935 | mutex_exit(&sc->sc_lock); |
948 | return 0; | | 936 | return 0; |
949 | } | | 937 | } |
950 | | | 938 | |
951 | static int | | 939 | static int |
952 | vhci_get_info(vhci_fd_t *vfd, struct vhci_ioc_get_info *args) | | 940 | vhci_get_info(vhci_fd_t *vfd, struct vhci_ioc_get_info *args) |
| @@ -1041,34 +1029,31 @@ vhci_fd_open(dev_t dev, int flags, int t | | | @@ -1041,34 +1029,31 @@ vhci_fd_open(dev_t dev, int flags, int t |
1041 | return error; | | 1029 | return error; |
1042 | | | 1030 | |
1043 | vfd = kmem_alloc(sizeof(*vfd), KM_SLEEP); | | 1031 | vfd = kmem_alloc(sizeof(*vfd), KM_SLEEP); |
1044 | vfd->port = 1; | | 1032 | vfd->port = 1; |
1045 | vfd->addr = 0; | | 1033 | vfd->addr = 0; |
1046 | vfd->softc = device_lookup_private(&vhci_cd, minor(dev)); | | 1034 | vfd->softc = device_lookup_private(&vhci_cd, minor(dev)); |
1047 | | | 1035 | |
1048 | return fd_clone(fp, fd, flags, &vhci_fileops, vfd); | | 1036 | return fd_clone(fp, fd, flags, &vhci_fileops, vfd); |
1049 | } | | 1037 | } |
1050 | | | 1038 | |
1051 | static int | | 1039 | static int |
1052 | vhci_fd_close(file_t *fp) | | 1040 | vhci_fd_close(file_t *fp) |
1053 | { | | 1041 | { |
1054 | struct vhci_ioc_usb_detach args; | | | |
1055 | vhci_fd_t *vfd = fp->f_data; | | 1042 | vhci_fd_t *vfd = fp->f_data; |
1056 | int ret __diagused; | | 1043 | int ret __diagused; |
1057 | | | 1044 | |
1058 | KASSERT(vfd != NULL); | | 1045 | KASSERT(vfd != NULL); |
1059 | | | 1046 | ret = vhci_usb_detach(vfd); |
1060 | args.port = vfd->port; | | | |
1061 | ret = vhci_usb_detach(vfd, &args); | | | |
1062 | KASSERT(ret == 0); | | 1047 | KASSERT(ret == 0); |
1063 | | | 1048 | |
1064 | kmem_free(vfd, sizeof(*vfd)); | | 1049 | kmem_free(vfd, sizeof(*vfd)); |
1065 | fp->f_data = NULL; | | 1050 | fp->f_data = NULL; |
1066 | | | 1051 | |
1067 | return 0; | | 1052 | return 0; |
1068 | } | | 1053 | } |
1069 | | | 1054 | |
1070 | static int | | 1055 | static int |
1071 | vhci_fd_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, | | 1056 | vhci_fd_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, |
1072 | int flags) | | 1057 | int flags) |
1073 | { | | 1058 | { |
1074 | vhci_fd_t *vfd = fp->f_data; | | 1059 | vhci_fd_t *vfd = fp->f_data; |
| @@ -1218,29 +1203,29 @@ vhci_fd_ioctl(file_t *fp, u_long cmd, vo | | | @@ -1218,29 +1203,29 @@ vhci_fd_ioctl(file_t *fp, u_long cmd, vo |
1218 | { | | 1203 | { |
1219 | vhci_fd_t *vfd = fp->f_data; | | 1204 | vhci_fd_t *vfd = fp->f_data; |
1220 | | | 1205 | |
1221 | KASSERT(vfd != NULL); | | 1206 | KASSERT(vfd != NULL); |
1222 | | | 1207 | |
1223 | switch (cmd) { | | 1208 | switch (cmd) { |
1224 | case VHCI_IOC_GET_INFO: | | 1209 | case VHCI_IOC_GET_INFO: |
1225 | return vhci_get_info(vfd, data); | | 1210 | return vhci_get_info(vfd, data); |
1226 | case VHCI_IOC_SET_PORT: | | 1211 | case VHCI_IOC_SET_PORT: |
1227 | return vhci_set_port(vfd, data); | | 1212 | return vhci_set_port(vfd, data); |
1228 | case VHCI_IOC_SET_ADDR: | | 1213 | case VHCI_IOC_SET_ADDR: |
1229 | return vhci_set_addr(vfd, data); | | 1214 | return vhci_set_addr(vfd, data); |
1230 | case VHCI_IOC_USB_ATTACH: | | 1215 | case VHCI_IOC_USB_ATTACH: |
1231 | return vhci_usb_attach(vfd, data); | | 1216 | return vhci_usb_attach(vfd); |
1232 | case VHCI_IOC_USB_DETACH: | | 1217 | case VHCI_IOC_USB_DETACH: |
1233 | return vhci_usb_detach(vfd, data); | | 1218 | return vhci_usb_detach(vfd); |
1234 | default: | | 1219 | default: |
1235 | return EINVAL; | | 1220 | return EINVAL; |
1236 | } | | 1221 | } |
1237 | } | | 1222 | } |
1238 | | | 1223 | |
1239 | /* -------------------------------------------------------------------------- */ | | 1224 | /* -------------------------------------------------------------------------- */ |
1240 | | | 1225 | |
1241 | static int vhci_match(device_t, cfdata_t, void *); | | 1226 | static int vhci_match(device_t, cfdata_t, void *); |
1242 | static void vhci_attach(device_t, device_t, void *); | | 1227 | static void vhci_attach(device_t, device_t, void *); |
1243 | static int vhci_activate(device_t, enum devact); | | 1228 | static int vhci_activate(device_t, enum devact); |
1244 | | | 1229 | |
1245 | CFATTACH_DECL_NEW(vhci, sizeof(vhci_softc_t), vhci_match, vhci_attach, | | 1230 | CFATTACH_DECL_NEW(vhci, sizeof(vhci_softc_t), vhci_match, vhci_attach, |
1246 | NULL, vhci_activate); | | 1231 | NULL, vhci_activate); |