| @@ -1,1515 +1,1515 @@ | | | @@ -1,1515 +1,1515 @@ |
1 | /* $NetBSD: umidi.c,v 1.63 2012/06/10 06:15:54 mrg Exp $ */ | | 1 | /* $NetBSD: umidi.c,v 1.64 2013/01/22 21:13:39 jmcneill Exp $ */ |
2 | /* | | 2 | /* |
3 | * Copyright (c) 2001, 2012 The NetBSD Foundation, Inc. | | 3 | * Copyright (c) 2001, 2012 The NetBSD Foundation, Inc. |
4 | * All rights reserved. | | 4 | * All rights reserved. |
5 | * | | 5 | * |
6 | * This code is derived from software contributed to The NetBSD Foundation | | 6 | * This code is derived from software contributed to The NetBSD Foundation |
7 | * by Takuya SHIOZAKI (tshiozak@NetBSD.org), (full-size transfers, extended | | 7 | * by Takuya SHIOZAKI (tshiozak@NetBSD.org), (full-size transfers, extended |
8 | * hw_if) Chapman Flack (chap@NetBSD.org), and Matthew R. Green | | 8 | * hw_if) Chapman Flack (chap@NetBSD.org), and Matthew R. Green |
9 | * (mrg@eterna.com.au). | | 9 | * (mrg@eterna.com.au). |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. | | 15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright | | 16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the | | 17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. | | 18 | * documentation and/or other materials provided with the distribution. |
19 | * | | 19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. | | 30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | #include <sys/cdefs.h> | | 33 | #include <sys/cdefs.h> |
34 | __KERNEL_RCSID(0, "$NetBSD: umidi.c,v 1.63 2012/06/10 06:15:54 mrg Exp $"); | | 34 | __KERNEL_RCSID(0, "$NetBSD: umidi.c,v 1.64 2013/01/22 21:13:39 jmcneill Exp $"); |
35 | | | 35 | |
36 | #include <sys/types.h> | | 36 | #include <sys/types.h> |
37 | #include <sys/param.h> | | 37 | #include <sys/param.h> |
38 | #include <sys/systm.h> | | 38 | #include <sys/systm.h> |
39 | #include <sys/kernel.h> | | 39 | #include <sys/kernel.h> |
40 | #include <sys/kmem.h> | | 40 | #include <sys/kmem.h> |
41 | #include <sys/device.h> | | 41 | #include <sys/device.h> |
42 | #include <sys/ioctl.h> | | 42 | #include <sys/ioctl.h> |
43 | #include <sys/conf.h> | | 43 | #include <sys/conf.h> |
44 | #include <sys/file.h> | | 44 | #include <sys/file.h> |
45 | #include <sys/select.h> | | 45 | #include <sys/select.h> |
46 | #include <sys/proc.h> | | 46 | #include <sys/proc.h> |
47 | #include <sys/vnode.h> | | 47 | #include <sys/vnode.h> |
48 | #include <sys/poll.h> | | 48 | #include <sys/poll.h> |
49 | #include <sys/intr.h> | | 49 | #include <sys/intr.h> |
50 | | | 50 | |
51 | #include <dev/usb/usb.h> | | 51 | #include <dev/usb/usb.h> |
52 | #include <dev/usb/usbdi.h> | | 52 | #include <dev/usb/usbdi.h> |
53 | #include <dev/usb/usbdi_util.h> | | 53 | #include <dev/usb/usbdi_util.h> |
54 | | | 54 | |
55 | #include <dev/auconv.h> | | 55 | #include <dev/auconv.h> |
56 | #include <dev/usb/usbdevs.h> | | 56 | #include <dev/usb/usbdevs.h> |
57 | #include <dev/usb/uaudioreg.h> | | 57 | #include <dev/usb/uaudioreg.h> |
58 | #include <dev/usb/umidireg.h> | | 58 | #include <dev/usb/umidireg.h> |
59 | #include <dev/usb/umidivar.h> | | 59 | #include <dev/usb/umidivar.h> |
60 | #include <dev/usb/umidi_quirks.h> | | 60 | #include <dev/usb/umidi_quirks.h> |
61 | | | 61 | |
62 | #include <dev/midi_if.h> | | 62 | #include <dev/midi_if.h> |
63 | | | 63 | |
64 | #ifdef UMIDI_DEBUG | | 64 | #ifdef UMIDI_DEBUG |
65 | #define DPRINTF(x) if (umididebug) printf x | | 65 | #define DPRINTF(x) if (umididebug) printf x |
66 | #define DPRINTFN(n,x) if (umididebug >= (n)) printf x | | 66 | #define DPRINTFN(n,x) if (umididebug >= (n)) printf x |
67 | #include <sys/time.h> | | 67 | #include <sys/time.h> |
68 | static struct timeval umidi_tv; | | 68 | static struct timeval umidi_tv; |
69 | int umididebug = 0; | | 69 | int umididebug = 0; |
70 | #else | | 70 | #else |
71 | #define DPRINTF(x) | | 71 | #define DPRINTF(x) |
72 | #define DPRINTFN(n,x) | | 72 | #define DPRINTFN(n,x) |
73 | #endif | | 73 | #endif |
74 | | | 74 | |
75 | #define UMIDI_ENDPOINT_SIZE(sc) (sizeof(*(sc)->sc_out_ep) * \ | | 75 | #define UMIDI_ENDPOINT_SIZE(sc) (sizeof(*(sc)->sc_out_ep) * \ |
76 | (sc->sc_out_num_endpoints + \ | | 76 | (sc->sc_out_num_endpoints + \ |
77 | sc->sc_in_num_endpoints)) | | 77 | sc->sc_in_num_endpoints)) |
78 | | | 78 | |
79 | | | 79 | |
80 | static int umidi_open(void *, int, | | 80 | static int umidi_open(void *, int, |
81 | void (*)(void *, int), void (*)(void *), void *); | | 81 | void (*)(void *, int), void (*)(void *), void *); |
82 | static void umidi_close(void *); | | 82 | static void umidi_close(void *); |
83 | static int umidi_channelmsg(void *, int, int, u_char *, int); | | 83 | static int umidi_channelmsg(void *, int, int, u_char *, int); |
84 | static int umidi_commonmsg(void *, int, u_char *, int); | | 84 | static int umidi_commonmsg(void *, int, u_char *, int); |
85 | static int umidi_sysex(void *, u_char *, int); | | 85 | static int umidi_sysex(void *, u_char *, int); |
86 | static int umidi_rtmsg(void *, int); | | 86 | static int umidi_rtmsg(void *, int); |
87 | static void umidi_getinfo(void *, struct midi_info *); | | 87 | static void umidi_getinfo(void *, struct midi_info *); |
88 | static void umidi_get_locks(void *, kmutex_t **, kmutex_t **); | | 88 | static void umidi_get_locks(void *, kmutex_t **, kmutex_t **); |
89 | | | 89 | |
90 | static usbd_status alloc_pipe(struct umidi_endpoint *); | | 90 | static usbd_status alloc_pipe(struct umidi_endpoint *); |
91 | static void free_pipe(struct umidi_endpoint *); | | 91 | static void free_pipe(struct umidi_endpoint *); |
92 | | | 92 | |
93 | static usbd_status alloc_all_endpoints(struct umidi_softc *); | | 93 | static usbd_status alloc_all_endpoints(struct umidi_softc *); |
94 | static void free_all_endpoints(struct umidi_softc *); | | 94 | static void free_all_endpoints(struct umidi_softc *); |
95 | | | 95 | |
96 | static usbd_status alloc_all_jacks(struct umidi_softc *); | | 96 | static usbd_status alloc_all_jacks(struct umidi_softc *); |
97 | static void free_all_jacks(struct umidi_softc *); | | 97 | static void free_all_jacks(struct umidi_softc *); |
98 | static usbd_status bind_jacks_to_mididev(struct umidi_softc *, | | 98 | static usbd_status bind_jacks_to_mididev(struct umidi_softc *, |
99 | struct umidi_jack *, | | 99 | struct umidi_jack *, |
100 | struct umidi_jack *, | | 100 | struct umidi_jack *, |
101 | struct umidi_mididev *); | | 101 | struct umidi_mididev *); |
102 | static void unbind_jacks_from_mididev(struct umidi_mididev *); | | 102 | static void unbind_jacks_from_mididev(struct umidi_mididev *); |
103 | static void unbind_all_jacks(struct umidi_softc *); | | 103 | static void unbind_all_jacks(struct umidi_softc *); |
104 | static usbd_status assign_all_jacks_automatically(struct umidi_softc *); | | 104 | static usbd_status assign_all_jacks_automatically(struct umidi_softc *); |
105 | static usbd_status open_out_jack(struct umidi_jack *, void *, | | 105 | static usbd_status open_out_jack(struct umidi_jack *, void *, |
106 | void (*)(void *)); | | 106 | void (*)(void *)); |
107 | static usbd_status open_in_jack(struct umidi_jack *, void *, | | 107 | static usbd_status open_in_jack(struct umidi_jack *, void *, |
108 | void (*)(void *, int)); | | 108 | void (*)(void *, int)); |
109 | static void close_out_jack(struct umidi_jack *); | | 109 | static void close_out_jack(struct umidi_jack *); |
110 | static void close_in_jack(struct umidi_jack *); | | 110 | static void close_in_jack(struct umidi_jack *); |
111 | | | 111 | |
112 | static usbd_status attach_mididev(struct umidi_softc *, struct umidi_mididev *); | | 112 | static usbd_status attach_mididev(struct umidi_softc *, struct umidi_mididev *); |
113 | static usbd_status detach_mididev(struct umidi_mididev *, int); | | 113 | static usbd_status detach_mididev(struct umidi_mididev *, int); |
114 | static void deactivate_mididev(struct umidi_mididev *); | | 114 | static void deactivate_mididev(struct umidi_mididev *); |
115 | static usbd_status alloc_all_mididevs(struct umidi_softc *, int); | | 115 | static usbd_status alloc_all_mididevs(struct umidi_softc *, int); |
116 | static void free_all_mididevs(struct umidi_softc *); | | 116 | static void free_all_mididevs(struct umidi_softc *); |
117 | static usbd_status attach_all_mididevs(struct umidi_softc *); | | 117 | static usbd_status attach_all_mididevs(struct umidi_softc *); |
118 | static usbd_status detach_all_mididevs(struct umidi_softc *, int); | | 118 | static usbd_status detach_all_mididevs(struct umidi_softc *, int); |
119 | static void deactivate_all_mididevs(struct umidi_softc *); | | 119 | static void deactivate_all_mididevs(struct umidi_softc *); |
120 | static void describe_mididev(struct umidi_mididev *); | | 120 | static void describe_mididev(struct umidi_mididev *); |
121 | | | 121 | |
122 | #ifdef UMIDI_DEBUG | | 122 | #ifdef UMIDI_DEBUG |
123 | static void dump_sc(struct umidi_softc *); | | 123 | static void dump_sc(struct umidi_softc *); |
124 | static void dump_ep(struct umidi_endpoint *); | | 124 | static void dump_ep(struct umidi_endpoint *); |
125 | static void dump_jack(struct umidi_jack *); | | 125 | static void dump_jack(struct umidi_jack *); |
126 | #endif | | 126 | #endif |
127 | | | 127 | |
128 | static usbd_status start_input_transfer(struct umidi_endpoint *); | | 128 | static usbd_status start_input_transfer(struct umidi_endpoint *); |
129 | static usbd_status start_output_transfer(struct umidi_endpoint *); | | 129 | static usbd_status start_output_transfer(struct umidi_endpoint *); |
130 | static int out_jack_output(struct umidi_jack *, u_char *, int, int); | | 130 | static int out_jack_output(struct umidi_jack *, u_char *, int, int); |
131 | static void in_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); | | 131 | static void in_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); |
132 | static void out_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); | | 132 | static void out_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); |
133 | static void out_solicit(void *); /* struct umidi_endpoint* for softintr */ | | 133 | static void out_solicit(void *); /* struct umidi_endpoint* for softintr */ |
134 | static void out_solicit_locked(void *); /* pre-locked version */ | | 134 | static void out_solicit_locked(void *); /* pre-locked version */ |
135 | | | 135 | |
136 | | | 136 | |
137 | const struct midi_hw_if umidi_hw_if = { | | 137 | const struct midi_hw_if umidi_hw_if = { |
138 | .open = umidi_open, | | 138 | .open = umidi_open, |
139 | .close = umidi_close, | | 139 | .close = umidi_close, |
140 | .output = umidi_rtmsg, | | 140 | .output = umidi_rtmsg, |
141 | .getinfo = umidi_getinfo, | | 141 | .getinfo = umidi_getinfo, |
142 | .get_locks = umidi_get_locks, | | 142 | .get_locks = umidi_get_locks, |
143 | }; | | 143 | }; |
144 | | | 144 | |
145 | struct midi_hw_if_ext umidi_hw_if_ext = { | | 145 | struct midi_hw_if_ext umidi_hw_if_ext = { |
146 | .channel = umidi_channelmsg, | | 146 | .channel = umidi_channelmsg, |
147 | .common = umidi_commonmsg, | | 147 | .common = umidi_commonmsg, |
148 | .sysex = umidi_sysex, | | 148 | .sysex = umidi_sysex, |
149 | }; | | 149 | }; |
150 | | | 150 | |
151 | struct midi_hw_if_ext umidi_hw_if_mm = { | | 151 | struct midi_hw_if_ext umidi_hw_if_mm = { |
152 | .channel = umidi_channelmsg, | | 152 | .channel = umidi_channelmsg, |
153 | .common = umidi_commonmsg, | | 153 | .common = umidi_commonmsg, |
154 | .sysex = umidi_sysex, | | 154 | .sysex = umidi_sysex, |
155 | .compress = 1, | | 155 | .compress = 1, |
156 | }; | | 156 | }; |
157 | | | 157 | |
158 | int umidi_match(device_t, cfdata_t, void *); | | 158 | int umidi_match(device_t, cfdata_t, void *); |
159 | void umidi_attach(device_t, device_t, void *); | | 159 | void umidi_attach(device_t, device_t, void *); |
160 | void umidi_childdet(device_t, device_t); | | 160 | void umidi_childdet(device_t, device_t); |
161 | int umidi_detach(device_t, int); | | 161 | int umidi_detach(device_t, int); |
162 | int umidi_activate(device_t, enum devact); | | 162 | int umidi_activate(device_t, enum devact); |
163 | extern struct cfdriver umidi_cd; | | 163 | extern struct cfdriver umidi_cd; |
164 | CFATTACH_DECL2_NEW(umidi, sizeof(struct umidi_softc), umidi_match, | | 164 | CFATTACH_DECL2_NEW(umidi, sizeof(struct umidi_softc), umidi_match, |
165 | umidi_attach, umidi_detach, umidi_activate, NULL, umidi_childdet); | | 165 | umidi_attach, umidi_detach, umidi_activate, NULL, umidi_childdet); |
166 | | | 166 | |
167 | int | | 167 | int |
168 | umidi_match(device_t parent, cfdata_t match, void *aux) | | 168 | umidi_match(device_t parent, cfdata_t match, void *aux) |
169 | { | | 169 | { |
170 | struct usbif_attach_arg *uaa = aux; | | 170 | struct usbif_attach_arg *uaa = aux; |
171 | | | 171 | |
172 | DPRINTFN(1,("umidi_match\n")); | | 172 | DPRINTFN(1,("umidi_match\n")); |
173 | | | 173 | |
174 | if (umidi_search_quirk(uaa->vendor, uaa->product, uaa->ifaceno)) | | 174 | if (umidi_search_quirk(uaa->vendor, uaa->product, uaa->ifaceno)) |
175 | return UMATCH_IFACECLASS_IFACESUBCLASS; | | 175 | return UMATCH_IFACECLASS_IFACESUBCLASS; |
176 | | | 176 | |
177 | if (uaa->class == UICLASS_AUDIO && | | 177 | if (uaa->class == UICLASS_AUDIO && |
178 | uaa->subclass == UISUBCLASS_MIDISTREAM) | | 178 | uaa->subclass == UISUBCLASS_MIDISTREAM) |
179 | return UMATCH_IFACECLASS_IFACESUBCLASS; | | 179 | return UMATCH_IFACECLASS_IFACESUBCLASS; |
180 | | | 180 | |
181 | return UMATCH_NONE; | | 181 | return UMATCH_NONE; |
182 | } | | 182 | } |
183 | | | 183 | |
184 | void | | 184 | void |
185 | umidi_attach(device_t parent, device_t self, void *aux) | | 185 | umidi_attach(device_t parent, device_t self, void *aux) |
186 | { | | 186 | { |
187 | usbd_status err; | | 187 | usbd_status err; |
188 | struct umidi_softc *sc = device_private(self); | | 188 | struct umidi_softc *sc = device_private(self); |
189 | struct usbif_attach_arg *uaa = aux; | | 189 | struct usbif_attach_arg *uaa = aux; |
190 | char *devinfop; | | 190 | char *devinfop; |
191 | | | 191 | |
192 | DPRINTFN(1,("umidi_attach\n")); | | 192 | DPRINTFN(1,("umidi_attach\n")); |
193 | | | 193 | |
194 | sc->sc_dev = self; | | 194 | sc->sc_dev = self; |
195 | | | 195 | |
196 | aprint_naive("\n"); | | 196 | aprint_naive("\n"); |
197 | aprint_normal("\n"); | | 197 | aprint_normal("\n"); |
198 | | | 198 | |
199 | devinfop = usbd_devinfo_alloc(uaa->device, 0); | | 199 | devinfop = usbd_devinfo_alloc(uaa->device, 0); |
200 | aprint_normal_dev(self, "%s\n", devinfop); | | 200 | aprint_normal_dev(self, "%s\n", devinfop); |
201 | usbd_devinfo_free(devinfop); | | 201 | usbd_devinfo_free(devinfop); |
202 | | | 202 | |
203 | sc->sc_iface = uaa->iface; | | 203 | sc->sc_iface = uaa->iface; |
204 | sc->sc_udev = uaa->device; | | 204 | sc->sc_udev = uaa->device; |
205 | | | 205 | |
206 | sc->sc_quirk = | | 206 | sc->sc_quirk = |
207 | umidi_search_quirk(uaa->vendor, uaa->product, uaa->ifaceno); | | 207 | umidi_search_quirk(uaa->vendor, uaa->product, uaa->ifaceno); |
208 | aprint_normal_dev(self, ""); | | 208 | aprint_normal_dev(self, ""); |
209 | umidi_print_quirk(sc->sc_quirk); | | 209 | umidi_print_quirk(sc->sc_quirk); |
210 | | | 210 | |
211 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_USB); | | 211 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_USB); |
212 | cv_init(&sc->sc_cv, "umidopcl"); | | 212 | cv_init(&sc->sc_cv, "umidopcl"); |
213 | | | 213 | |
214 | err = alloc_all_endpoints(sc); | | 214 | err = alloc_all_endpoints(sc); |
215 | if (err != USBD_NORMAL_COMPLETION) { | | 215 | if (err != USBD_NORMAL_COMPLETION) { |
216 | aprint_error_dev(self, | | 216 | aprint_error_dev(self, |
217 | "alloc_all_endpoints failed. (err=%d)\n", err); | | 217 | "alloc_all_endpoints failed. (err=%d)\n", err); |
218 | goto error; | | 218 | goto error; |
219 | } | | 219 | } |
220 | err = alloc_all_jacks(sc); | | 220 | err = alloc_all_jacks(sc); |
221 | if (err != USBD_NORMAL_COMPLETION) { | | 221 | if (err != USBD_NORMAL_COMPLETION) { |
222 | free_all_endpoints(sc); | | 222 | free_all_endpoints(sc); |
223 | aprint_error_dev(self, "alloc_all_jacks failed. (err=%d)\n", | | 223 | aprint_error_dev(self, "alloc_all_jacks failed. (err=%d)\n", |
224 | err); | | 224 | err); |
225 | goto error; | | 225 | goto error; |
226 | } | | 226 | } |
227 | aprint_normal_dev(self, "out=%d, in=%d\n", | | 227 | aprint_normal_dev(self, "out=%d, in=%d\n", |
228 | sc->sc_out_num_jacks, sc->sc_in_num_jacks); | | 228 | sc->sc_out_num_jacks, sc->sc_in_num_jacks); |
229 | | | 229 | |
230 | err = assign_all_jacks_automatically(sc); | | 230 | err = assign_all_jacks_automatically(sc); |
231 | if (err != USBD_NORMAL_COMPLETION) { | | 231 | if (err != USBD_NORMAL_COMPLETION) { |
232 | unbind_all_jacks(sc); | | 232 | unbind_all_jacks(sc); |
233 | free_all_jacks(sc); | | 233 | free_all_jacks(sc); |
234 | free_all_endpoints(sc); | | 234 | free_all_endpoints(sc); |
235 | aprint_error_dev(self, | | 235 | aprint_error_dev(self, |
236 | "assign_all_jacks_automatically failed. (err=%d)\n", err); | | 236 | "assign_all_jacks_automatically failed. (err=%d)\n", err); |
237 | goto error; | | 237 | goto error; |
238 | } | | 238 | } |
239 | err = attach_all_mididevs(sc); | | 239 | err = attach_all_mididevs(sc); |
240 | if (err != USBD_NORMAL_COMPLETION) { | | 240 | if (err != USBD_NORMAL_COMPLETION) { |
241 | free_all_jacks(sc); | | 241 | free_all_jacks(sc); |
242 | free_all_endpoints(sc); | | 242 | free_all_endpoints(sc); |
243 | aprint_error_dev(self, | | 243 | aprint_error_dev(self, |
244 | "attach_all_mididevs failed. (err=%d)\n", err); | | 244 | "attach_all_mididevs failed. (err=%d)\n", err); |
245 | } | | 245 | } |
246 | | | 246 | |
247 | #ifdef UMIDI_DEBUG | | 247 | #ifdef UMIDI_DEBUG |
248 | dump_sc(sc); | | 248 | dump_sc(sc); |
249 | #endif | | 249 | #endif |
250 | | | 250 | |
251 | usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, | | 251 | usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, |
252 | sc->sc_udev, sc->sc_dev); | | 252 | sc->sc_udev, sc->sc_dev); |
253 | | | 253 | |
254 | return; | | 254 | return; |
255 | error: | | 255 | error: |
256 | aprint_error_dev(self, "disabled.\n"); | | 256 | aprint_error_dev(self, "disabled.\n"); |
257 | sc->sc_dying = 1; | | 257 | sc->sc_dying = 1; |
258 | KERNEL_UNLOCK_ONE(curlwp); | | 258 | KERNEL_UNLOCK_ONE(curlwp); |
259 | return; | | 259 | return; |
260 | } | | 260 | } |
261 | | | 261 | |
262 | void | | 262 | void |
263 | umidi_childdet(device_t self, device_t child) | | 263 | umidi_childdet(device_t self, device_t child) |
264 | { | | 264 | { |
265 | int i; | | 265 | int i; |
266 | struct umidi_softc *sc = device_private(self); | | 266 | struct umidi_softc *sc = device_private(self); |
267 | | | 267 | |
268 | KASSERT(sc->sc_mididevs != NULL); | | 268 | KASSERT(sc->sc_mididevs != NULL); |
269 | | | 269 | |
270 | for (i = 0; i < sc->sc_num_mididevs; i++) { | | 270 | for (i = 0; i < sc->sc_num_mididevs; i++) { |
271 | if (sc->sc_mididevs[i].mdev == child) | | 271 | if (sc->sc_mididevs[i].mdev == child) |
272 | break; | | 272 | break; |
273 | } | | 273 | } |
274 | KASSERT(i < sc->sc_num_mididevs); | | 274 | KASSERT(i < sc->sc_num_mididevs); |
275 | sc->sc_mididevs[i].mdev = NULL; | | 275 | sc->sc_mididevs[i].mdev = NULL; |
276 | } | | 276 | } |
277 | | | 277 | |
278 | int | | 278 | int |
279 | umidi_activate(device_t self, enum devact act) | | 279 | umidi_activate(device_t self, enum devact act) |
280 | { | | 280 | { |
281 | struct umidi_softc *sc = device_private(self); | | 281 | struct umidi_softc *sc = device_private(self); |
282 | | | 282 | |
283 | switch (act) { | | 283 | switch (act) { |
284 | case DVACT_DEACTIVATE: | | 284 | case DVACT_DEACTIVATE: |
285 | DPRINTFN(1,("umidi_activate (deactivate)\n")); | | 285 | DPRINTFN(1,("umidi_activate (deactivate)\n")); |
286 | sc->sc_dying = 1; | | 286 | sc->sc_dying = 1; |
287 | deactivate_all_mididevs(sc); | | 287 | deactivate_all_mididevs(sc); |
288 | return 0; | | 288 | return 0; |
289 | default: | | 289 | default: |
290 | DPRINTFN(1,("umidi_activate (%d)\n", act)); | | 290 | DPRINTFN(1,("umidi_activate (%d)\n", act)); |
291 | return EOPNOTSUPP; | | 291 | return EOPNOTSUPP; |
292 | } | | 292 | } |
293 | } | | 293 | } |
294 | | | 294 | |
295 | int | | 295 | int |
296 | umidi_detach(device_t self, int flags) | | 296 | umidi_detach(device_t self, int flags) |
297 | { | | 297 | { |
298 | struct umidi_softc *sc = device_private(self); | | 298 | struct umidi_softc *sc = device_private(self); |
299 | | | 299 | |
300 | DPRINTFN(1,("umidi_detach\n")); | | 300 | DPRINTFN(1,("umidi_detach\n")); |
301 | | | 301 | |
302 | sc->sc_dying = 1; | | 302 | sc->sc_dying = 1; |
303 | detach_all_mididevs(sc, flags); | | 303 | detach_all_mididevs(sc, flags); |
304 | free_all_mididevs(sc); | | 304 | free_all_mididevs(sc); |
305 | free_all_jacks(sc); | | 305 | free_all_jacks(sc); |
306 | free_all_endpoints(sc); | | 306 | free_all_endpoints(sc); |
307 | | | 307 | |
308 | usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, | | 308 | usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, |
309 | sc->sc_dev); | | 309 | sc->sc_dev); |
310 | | | 310 | |
311 | mutex_destroy(&sc->sc_lock); | | 311 | mutex_destroy(&sc->sc_lock); |
312 | cv_destroy(&sc->sc_cv); | | 312 | cv_destroy(&sc->sc_cv); |
313 | | | 313 | |
314 | return 0; | | 314 | return 0; |
315 | } | | 315 | } |
316 | | | 316 | |
317 | | | 317 | |
318 | /* | | 318 | /* |
319 | * midi_if stuffs | | 319 | * midi_if stuffs |
320 | */ | | 320 | */ |
321 | int | | 321 | int |
322 | umidi_open(void *addr, | | 322 | umidi_open(void *addr, |
323 | int flags, | | 323 | int flags, |
324 | void (*iintr)(void *, int), | | 324 | void (*iintr)(void *, int), |
325 | void (*ointr)(void *), | | 325 | void (*ointr)(void *), |
326 | void *arg) | | 326 | void *arg) |
327 | { | | 327 | { |
328 | struct umidi_mididev *mididev = addr; | | 328 | struct umidi_mididev *mididev = addr; |
329 | struct umidi_softc *sc = mididev->sc; | | 329 | struct umidi_softc *sc = mididev->sc; |
330 | usbd_status err; | | 330 | usbd_status err; |
331 | | | 331 | |
332 | DPRINTF(("umidi_open: sc=%p\n", sc)); | | 332 | DPRINTF(("umidi_open: sc=%p\n", sc)); |
333 | | | 333 | |
334 | if (!sc) | | 334 | if (!sc) |
335 | return ENXIO; | | 335 | return ENXIO; |
336 | if (mididev->opened) | | 336 | if (mididev->opened) |
337 | return EBUSY; | | 337 | return EBUSY; |
338 | if (sc->sc_dying) | | 338 | if (sc->sc_dying) |
339 | return EIO; | | 339 | return EIO; |
340 | | | 340 | |
341 | mididev->opened = 1; | | 341 | mididev->opened = 1; |
342 | mididev->closing = 0; | | 342 | mididev->closing = 0; |
343 | mididev->flags = flags; | | 343 | mididev->flags = flags; |
344 | if ((mididev->flags & FWRITE) && mididev->out_jack) { | | 344 | if ((mididev->flags & FWRITE) && mididev->out_jack) { |
345 | err = open_out_jack(mididev->out_jack, arg, ointr); | | 345 | err = open_out_jack(mididev->out_jack, arg, ointr); |
346 | if ( err != USBD_NORMAL_COMPLETION ) | | 346 | if ( err != USBD_NORMAL_COMPLETION ) |
347 | goto bad; | | 347 | goto bad; |
348 | } | | 348 | } |
349 | if ((mididev->flags & FREAD) && mididev->in_jack) { | | 349 | if ((mididev->flags & FREAD) && mididev->in_jack) { |
350 | err = open_in_jack(mididev->in_jack, arg, iintr); | | 350 | err = open_in_jack(mididev->in_jack, arg, iintr); |
351 | if ( err != USBD_NORMAL_COMPLETION | | 351 | if ( err != USBD_NORMAL_COMPLETION |
352 | && err != USBD_IN_PROGRESS ) | | 352 | && err != USBD_IN_PROGRESS ) |
353 | goto bad; | | 353 | goto bad; |
354 | } | | 354 | } |
355 | | | 355 | |
356 | return 0; | | 356 | return 0; |
357 | bad: | | 357 | bad: |
358 | mididev->opened = 0; | | 358 | mididev->opened = 0; |
359 | DPRINTF(("umidi_open: usbd_status %d\n", err)); | | 359 | DPRINTF(("umidi_open: usbd_status %d\n", err)); |
360 | return USBD_IN_USE == err ? EBUSY : EIO; | | 360 | return USBD_IN_USE == err ? EBUSY : EIO; |
361 | } | | 361 | } |
362 | | | 362 | |
363 | void | | 363 | void |
364 | umidi_close(void *addr) | | 364 | umidi_close(void *addr) |
365 | { | | 365 | { |
366 | struct umidi_mididev *mididev = addr; | | 366 | struct umidi_mididev *mididev = addr; |
367 | | | 367 | |
368 | mididev->closing = 1; | | 368 | mididev->closing = 1; |
369 | | | 369 | |
370 | mutex_spin_exit(&mididev->sc->sc_lock); | | 370 | mutex_spin_exit(&mididev->sc->sc_lock); |
371 | | | 371 | |
372 | if ((mididev->flags & FWRITE) && mididev->out_jack) | | 372 | if ((mididev->flags & FWRITE) && mididev->out_jack) |
373 | close_out_jack(mididev->out_jack); | | 373 | close_out_jack(mididev->out_jack); |
374 | if ((mididev->flags & FREAD) && mididev->in_jack) | | 374 | if ((mididev->flags & FREAD) && mididev->in_jack) |
375 | close_in_jack(mididev->in_jack); | | 375 | close_in_jack(mididev->in_jack); |
376 | | | 376 | |
377 | mutex_spin_enter(&mididev->sc->sc_lock); | | 377 | mutex_spin_enter(&mididev->sc->sc_lock); |
378 | | | 378 | |
379 | mididev->opened = 0; | | 379 | mididev->opened = 0; |
380 | } | | 380 | } |
381 | | | 381 | |
382 | int | | 382 | int |
383 | umidi_channelmsg(void *addr, int status, int channel, u_char *msg, | | 383 | umidi_channelmsg(void *addr, int status, int channel, u_char *msg, |
384 | int len) | | 384 | int len) |
385 | { | | 385 | { |
386 | struct umidi_mididev *mididev = addr; | | 386 | struct umidi_mididev *mididev = addr; |
387 | | | 387 | |
388 | if (!mididev->out_jack || !mididev->opened || mididev->closing) | | 388 | if (!mididev->out_jack || !mididev->opened || mididev->closing) |
389 | return EIO; | | 389 | return EIO; |
390 | | | 390 | |
391 | return out_jack_output(mididev->out_jack, msg, len, (status>>4)&0xf); | | 391 | return out_jack_output(mididev->out_jack, msg, len, (status>>4)&0xf); |
392 | } | | 392 | } |
393 | | | 393 | |
394 | int | | 394 | int |
395 | umidi_commonmsg(void *addr, int status, u_char *msg, int len) | | 395 | umidi_commonmsg(void *addr, int status, u_char *msg, int len) |
396 | { | | 396 | { |
397 | struct umidi_mididev *mididev = addr; | | 397 | struct umidi_mididev *mididev = addr; |
398 | int cin; | | 398 | int cin; |
399 | | | 399 | |
400 | if (!mididev->out_jack || !mididev->opened || mididev->closing) | | 400 | if (!mididev->out_jack || !mididev->opened || mididev->closing) |
401 | return EIO; | | 401 | return EIO; |
402 | | | 402 | |
403 | switch ( len ) { | | 403 | switch ( len ) { |
404 | case 1: cin = 5; break; | | 404 | case 1: cin = 5; break; |
405 | case 2: cin = 2; break; | | 405 | case 2: cin = 2; break; |
406 | case 3: cin = 3; break; | | 406 | case 3: cin = 3; break; |
407 | default: return EIO; /* or gcc warns of cin uninitialized */ | | 407 | default: return EIO; /* or gcc warns of cin uninitialized */ |
408 | } | | 408 | } |
409 | | | 409 | |
410 | return out_jack_output(mididev->out_jack, msg, len, cin); | | 410 | return out_jack_output(mididev->out_jack, msg, len, cin); |
411 | } | | 411 | } |
412 | | | 412 | |
413 | int | | 413 | int |
414 | umidi_sysex(void *addr, u_char *msg, int len) | | 414 | umidi_sysex(void *addr, u_char *msg, int len) |
415 | { | | 415 | { |
416 | struct umidi_mididev *mididev = addr; | | 416 | struct umidi_mididev *mididev = addr; |
417 | int cin; | | 417 | int cin; |
418 | | | 418 | |
419 | if (!mididev->out_jack || !mididev->opened || mididev->closing) | | 419 | if (!mididev->out_jack || !mididev->opened || mididev->closing) |
420 | return EIO; | | 420 | return EIO; |
421 | | | 421 | |
422 | switch ( len ) { | | 422 | switch ( len ) { |
423 | case 1: cin = 5; break; | | 423 | case 1: cin = 5; break; |
424 | case 2: cin = 6; break; | | 424 | case 2: cin = 6; break; |
425 | case 3: cin = (msg[2] == 0xf7) ? 7 : 4; break; | | 425 | case 3: cin = (msg[2] == 0xf7) ? 7 : 4; break; |
426 | default: return EIO; /* or gcc warns of cin uninitialized */ | | 426 | default: return EIO; /* or gcc warns of cin uninitialized */ |
427 | } | | 427 | } |
428 | | | 428 | |
429 | return out_jack_output(mididev->out_jack, msg, len, cin); | | 429 | return out_jack_output(mididev->out_jack, msg, len, cin); |
430 | } | | 430 | } |
431 | | | 431 | |
432 | int | | 432 | int |
433 | umidi_rtmsg(void *addr, int d) | | 433 | umidi_rtmsg(void *addr, int d) |
434 | { | | 434 | { |
435 | struct umidi_mididev *mididev = addr; | | 435 | struct umidi_mididev *mididev = addr; |
436 | u_char msg = d; | | 436 | u_char msg = d; |
437 | | | 437 | |
438 | if (!mididev->out_jack || !mididev->opened || mididev->closing) | | 438 | if (!mididev->out_jack || !mididev->opened || mididev->closing) |
439 | return EIO; | | 439 | return EIO; |
440 | | | 440 | |
441 | return out_jack_output(mididev->out_jack, &msg, 1, 0xf); | | 441 | return out_jack_output(mididev->out_jack, &msg, 1, 0xf); |
442 | } | | 442 | } |
443 | | | 443 | |
444 | void | | 444 | void |
445 | umidi_getinfo(void *addr, struct midi_info *mi) | | 445 | umidi_getinfo(void *addr, struct midi_info *mi) |
446 | { | | 446 | { |
447 | struct umidi_mididev *mididev = addr; | | 447 | struct umidi_mididev *mididev = addr; |
448 | struct umidi_softc *sc = mididev->sc; | | 448 | struct umidi_softc *sc = mididev->sc; |
449 | int mm = UMQ_ISTYPE(sc, UMQ_TYPE_MIDIMAN_GARBLE); | | 449 | int mm = UMQ_ISTYPE(sc, UMQ_TYPE_MIDIMAN_GARBLE); |
450 | | | 450 | |
451 | mi->name = mididev->label; | | 451 | mi->name = mididev->label; |
452 | mi->props = MIDI_PROP_OUT_INTR; | | 452 | mi->props = MIDI_PROP_OUT_INTR; |
453 | if (mididev->in_jack) | | 453 | if (mididev->in_jack) |
454 | mi->props |= MIDI_PROP_CAN_INPUT; | | 454 | mi->props |= MIDI_PROP_CAN_INPUT; |
455 | midi_register_hw_if_ext(mm? &umidi_hw_if_mm : &umidi_hw_if_ext); | | 455 | midi_register_hw_if_ext(mm? &umidi_hw_if_mm : &umidi_hw_if_ext); |
456 | } | | 456 | } |
457 | | | 457 | |
458 | static void | | 458 | static void |
459 | umidi_get_locks(void *addr, kmutex_t **thread, kmutex_t **intr) | | 459 | umidi_get_locks(void *addr, kmutex_t **thread, kmutex_t **intr) |
460 | { | | 460 | { |
461 | struct umidi_mididev *mididev = addr; | | 461 | struct umidi_mididev *mididev = addr; |
462 | struct umidi_softc *sc = mididev->sc; | | 462 | struct umidi_softc *sc = mididev->sc; |
463 | | | 463 | |
464 | *intr = NULL; | | 464 | *intr = NULL; |
465 | *thread = &sc->sc_lock; | | 465 | *thread = &sc->sc_lock; |
466 | } | | 466 | } |
467 | | | 467 | |
468 | /* | | 468 | /* |
469 | * each endpoint stuffs | | 469 | * each endpoint stuffs |
470 | */ | | 470 | */ |
471 | | | 471 | |
472 | /* alloc/free pipe */ | | 472 | /* alloc/free pipe */ |
473 | static usbd_status | | 473 | static usbd_status |
474 | alloc_pipe(struct umidi_endpoint *ep) | | 474 | alloc_pipe(struct umidi_endpoint *ep) |
475 | { | | 475 | { |
476 | struct umidi_softc *sc = ep->sc; | | 476 | struct umidi_softc *sc = ep->sc; |
477 | usbd_status err; | | 477 | usbd_status err; |
478 | usb_endpoint_descriptor_t *epd; | | 478 | usb_endpoint_descriptor_t *epd; |
479 | | | 479 | |
480 | epd = usbd_get_endpoint_descriptor(sc->sc_iface, ep->addr); | | 480 | epd = usbd_get_endpoint_descriptor(sc->sc_iface, ep->addr); |
481 | /* | | 481 | /* |
482 | * For output, an improvement would be to have a buffer bigger than | | 482 | * For output, an improvement would be to have a buffer bigger than |
483 | * wMaxPacketSize by num_jacks-1 additional packet slots; that would | | 483 | * wMaxPacketSize by num_jacks-1 additional packet slots; that would |
484 | * allow out_solicit to fill the buffer to the full packet size in | | 484 | * allow out_solicit to fill the buffer to the full packet size in |
485 | * all cases. But to use usbd_alloc_buffer to get a slightly larger | | 485 | * all cases. But to use usbd_alloc_buffer to get a slightly larger |
486 | * buffer would not be a good way to do that, because if the addition | | 486 | * buffer would not be a good way to do that, because if the addition |
487 | * would make the buffer exceed USB_MEM_SMALL then a substantially | | 487 | * would make the buffer exceed USB_MEM_SMALL then a substantially |
488 | * larger block may be wastefully allocated. Some flavor of double | | 488 | * larger block may be wastefully allocated. Some flavor of double |
489 | * buffering could serve the same purpose, but would increase the | | 489 | * buffering could serve the same purpose, but would increase the |
490 | * code complexity, so for now I will live with the current slight | | 490 | * code complexity, so for now I will live with the current slight |
491 | * penalty of reducing max transfer size by (num_open-num_scheduled) | | 491 | * penalty of reducing max transfer size by (num_open-num_scheduled) |
492 | * packet slots. | | 492 | * packet slots. |
493 | */ | | 493 | */ |
494 | ep->buffer_size = UGETW(epd->wMaxPacketSize); | | 494 | ep->buffer_size = UGETW(epd->wMaxPacketSize); |
495 | ep->buffer_size -= ep->buffer_size % UMIDI_PACKET_SIZE; | | 495 | ep->buffer_size -= ep->buffer_size % UMIDI_PACKET_SIZE; |
496 | | | 496 | |
497 | DPRINTF(("%s: alloc_pipe %p, buffer size %u\n", | | 497 | DPRINTF(("%s: alloc_pipe %p, buffer size %u\n", |
498 | device_xname(sc->sc_dev), ep, ep->buffer_size)); | | 498 | device_xname(sc->sc_dev), ep, ep->buffer_size)); |
499 | ep->num_scheduled = 0; | | 499 | ep->num_scheduled = 0; |
500 | ep->this_schedule = 0; | | 500 | ep->this_schedule = 0; |
501 | ep->next_schedule = 0; | | 501 | ep->next_schedule = 0; |
502 | ep->soliciting = 0; | | 502 | ep->soliciting = 0; |
503 | ep->armed = 0; | | 503 | ep->armed = 0; |
504 | ep->xfer = usbd_alloc_xfer(sc->sc_udev); | | 504 | ep->xfer = usbd_alloc_xfer(sc->sc_udev); |
505 | if (ep->xfer == NULL) { | | 505 | if (ep->xfer == NULL) { |
506 | err = USBD_NOMEM; | | 506 | err = USBD_NOMEM; |
507 | goto quit; | | 507 | goto quit; |
508 | } | | 508 | } |
509 | ep->buffer = usbd_alloc_buffer(ep->xfer, ep->buffer_size); | | 509 | ep->buffer = usbd_alloc_buffer(ep->xfer, ep->buffer_size); |
510 | if (ep->buffer == NULL) { | | 510 | if (ep->buffer == NULL) { |
511 | usbd_free_xfer(ep->xfer); | | 511 | usbd_free_xfer(ep->xfer); |
512 | err = USBD_NOMEM; | | 512 | err = USBD_NOMEM; |
513 | goto quit; | | 513 | goto quit; |
514 | } | | 514 | } |
515 | ep->next_slot = ep->buffer; | | 515 | ep->next_slot = ep->buffer; |
516 | err = usbd_open_pipe(sc->sc_iface, ep->addr, 0, &ep->pipe); | | 516 | err = usbd_open_pipe(sc->sc_iface, ep->addr, USBD_MPSAFE, &ep->pipe); |
517 | if (err) | | 517 | if (err) |
518 | usbd_free_xfer(ep->xfer); | | 518 | usbd_free_xfer(ep->xfer); |
519 | ep->solicit_cookie = softint_establish(SOFTINT_CLOCK, out_solicit, ep); | | 519 | ep->solicit_cookie = softint_establish(SOFTINT_CLOCK, out_solicit, ep); |
520 | quit: | | 520 | quit: |
521 | return err; | | 521 | return err; |
522 | } | | 522 | } |
523 | | | 523 | |
524 | static void | | 524 | static void |
525 | free_pipe(struct umidi_endpoint *ep) | | 525 | free_pipe(struct umidi_endpoint *ep) |
526 | { | | 526 | { |
527 | DPRINTF(("%s: free_pipe %p\n", device_xname(ep->sc->sc_dev), ep)); | | 527 | DPRINTF(("%s: free_pipe %p\n", device_xname(ep->sc->sc_dev), ep)); |
528 | usbd_abort_pipe(ep->pipe); | | 528 | usbd_abort_pipe(ep->pipe); |
529 | usbd_close_pipe(ep->pipe); | | 529 | usbd_close_pipe(ep->pipe); |
530 | usbd_free_xfer(ep->xfer); | | 530 | usbd_free_xfer(ep->xfer); |
531 | softint_disestablish(ep->solicit_cookie); | | 531 | softint_disestablish(ep->solicit_cookie); |
532 | } | | 532 | } |
533 | | | 533 | |
534 | | | 534 | |
535 | /* alloc/free the array of endpoint structures */ | | 535 | /* alloc/free the array of endpoint structures */ |
536 | | | 536 | |
537 | static usbd_status alloc_all_endpoints_fixed_ep(struct umidi_softc *); | | 537 | static usbd_status alloc_all_endpoints_fixed_ep(struct umidi_softc *); |
538 | static usbd_status alloc_all_endpoints_yamaha(struct umidi_softc *); | | 538 | static usbd_status alloc_all_endpoints_yamaha(struct umidi_softc *); |
539 | static usbd_status alloc_all_endpoints_genuine(struct umidi_softc *); | | 539 | static usbd_status alloc_all_endpoints_genuine(struct umidi_softc *); |
540 | | | 540 | |
541 | static usbd_status | | 541 | static usbd_status |
542 | alloc_all_endpoints(struct umidi_softc *sc) | | 542 | alloc_all_endpoints(struct umidi_softc *sc) |
543 | { | | 543 | { |
544 | usbd_status err; | | 544 | usbd_status err; |
545 | struct umidi_endpoint *ep; | | 545 | struct umidi_endpoint *ep; |
546 | int i; | | 546 | int i; |
547 | | | 547 | |
548 | if (UMQ_ISTYPE(sc, UMQ_TYPE_FIXED_EP)) { | | 548 | if (UMQ_ISTYPE(sc, UMQ_TYPE_FIXED_EP)) { |
549 | err = alloc_all_endpoints_fixed_ep(sc); | | 549 | err = alloc_all_endpoints_fixed_ep(sc); |
550 | } else if (UMQ_ISTYPE(sc, UMQ_TYPE_YAMAHA)) { | | 550 | } else if (UMQ_ISTYPE(sc, UMQ_TYPE_YAMAHA)) { |
551 | err = alloc_all_endpoints_yamaha(sc); | | 551 | err = alloc_all_endpoints_yamaha(sc); |
552 | } else { | | 552 | } else { |
553 | err = alloc_all_endpoints_genuine(sc); | | 553 | err = alloc_all_endpoints_genuine(sc); |
554 | } | | 554 | } |
555 | if (err != USBD_NORMAL_COMPLETION) | | 555 | if (err != USBD_NORMAL_COMPLETION) |
556 | return err; | | 556 | return err; |
557 | | | 557 | |
558 | ep = sc->sc_endpoints; | | 558 | ep = sc->sc_endpoints; |
559 | for (i = sc->sc_out_num_endpoints+sc->sc_in_num_endpoints; i > 0; i--) { | | 559 | for (i = sc->sc_out_num_endpoints+sc->sc_in_num_endpoints; i > 0; i--) { |
560 | err = alloc_pipe(ep++); | | 560 | err = alloc_pipe(ep++); |
561 | if (err != USBD_NORMAL_COMPLETION) { | | 561 | if (err != USBD_NORMAL_COMPLETION) { |
562 | for (; ep != sc->sc_endpoints; ep--) | | 562 | for (; ep != sc->sc_endpoints; ep--) |
563 | free_pipe(ep-1); | | 563 | free_pipe(ep-1); |
564 | kmem_free(sc->sc_endpoints, sc->sc_endpoints_len); | | 564 | kmem_free(sc->sc_endpoints, sc->sc_endpoints_len); |
565 | sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL; | | 565 | sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL; |
566 | break; | | 566 | break; |
567 | } | | 567 | } |
568 | } | | 568 | } |
569 | return err; | | 569 | return err; |
570 | } | | 570 | } |
571 | | | 571 | |
572 | static void | | 572 | static void |
573 | free_all_endpoints(struct umidi_softc *sc) | | 573 | free_all_endpoints(struct umidi_softc *sc) |
574 | { | | 574 | { |
575 | int i; | | 575 | int i; |
576 | | | 576 | |
577 | for (i=0; i<sc->sc_in_num_endpoints+sc->sc_out_num_endpoints; i++) | | 577 | for (i=0; i<sc->sc_in_num_endpoints+sc->sc_out_num_endpoints; i++) |
578 | free_pipe(&sc->sc_endpoints[i]); | | 578 | free_pipe(&sc->sc_endpoints[i]); |
579 | if (sc->sc_endpoints != NULL) | | 579 | if (sc->sc_endpoints != NULL) |
580 | kmem_free(sc->sc_endpoints, sc->sc_endpoints_len); | | 580 | kmem_free(sc->sc_endpoints, sc->sc_endpoints_len); |
581 | sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL; | | 581 | sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL; |
582 | } | | 582 | } |
583 | | | 583 | |
584 | static usbd_status | | 584 | static usbd_status |
585 | alloc_all_endpoints_fixed_ep(struct umidi_softc *sc) | | 585 | alloc_all_endpoints_fixed_ep(struct umidi_softc *sc) |
586 | { | | 586 | { |
587 | usbd_status err; | | 587 | usbd_status err; |
588 | const struct umq_fixed_ep_desc *fp; | | 588 | const struct umq_fixed_ep_desc *fp; |
589 | struct umidi_endpoint *ep; | | 589 | struct umidi_endpoint *ep; |
590 | usb_endpoint_descriptor_t *epd; | | 590 | usb_endpoint_descriptor_t *epd; |
591 | int i; | | 591 | int i; |
592 | | | 592 | |
593 | fp = umidi_get_quirk_data_from_type(sc->sc_quirk, | | 593 | fp = umidi_get_quirk_data_from_type(sc->sc_quirk, |
594 | UMQ_TYPE_FIXED_EP); | | 594 | UMQ_TYPE_FIXED_EP); |
595 | sc->sc_out_num_jacks = 0; | | 595 | sc->sc_out_num_jacks = 0; |
596 | sc->sc_in_num_jacks = 0; | | 596 | sc->sc_in_num_jacks = 0; |
597 | sc->sc_out_num_endpoints = fp->num_out_ep; | | 597 | sc->sc_out_num_endpoints = fp->num_out_ep; |
598 | sc->sc_in_num_endpoints = fp->num_in_ep; | | 598 | sc->sc_in_num_endpoints = fp->num_in_ep; |
599 | sc->sc_endpoints_len = UMIDI_ENDPOINT_SIZE(sc); | | 599 | sc->sc_endpoints_len = UMIDI_ENDPOINT_SIZE(sc); |
600 | sc->sc_endpoints = kmem_zalloc(sc->sc_endpoints_len, KM_SLEEP); | | 600 | sc->sc_endpoints = kmem_zalloc(sc->sc_endpoints_len, KM_SLEEP); |
601 | if (!sc->sc_endpoints) | | 601 | if (!sc->sc_endpoints) |
602 | return USBD_NOMEM; | | 602 | return USBD_NOMEM; |
603 | | | 603 | |
604 | sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL; | | 604 | sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL; |
605 | sc->sc_in_ep = | | 605 | sc->sc_in_ep = |
606 | sc->sc_in_num_endpoints ? | | 606 | sc->sc_in_num_endpoints ? |
607 | sc->sc_endpoints+sc->sc_out_num_endpoints : NULL; | | 607 | sc->sc_endpoints+sc->sc_out_num_endpoints : NULL; |
608 | | | 608 | |
609 | ep = &sc->sc_out_ep[0]; | | 609 | ep = &sc->sc_out_ep[0]; |
610 | for (i = 0; i < sc->sc_out_num_endpoints; i++) { | | 610 | for (i = 0; i < sc->sc_out_num_endpoints; i++) { |
611 | epd = usbd_interface2endpoint_descriptor( | | 611 | epd = usbd_interface2endpoint_descriptor( |
612 | sc->sc_iface, | | 612 | sc->sc_iface, |
613 | fp->out_ep[i].ep); | | 613 | fp->out_ep[i].ep); |
614 | if (!epd) { | | 614 | if (!epd) { |
615 | aprint_error_dev(sc->sc_dev, | | 615 | aprint_error_dev(sc->sc_dev, |
616 | "cannot get endpoint descriptor(out:%d)\n", | | 616 | "cannot get endpoint descriptor(out:%d)\n", |
617 | fp->out_ep[i].ep); | | 617 | fp->out_ep[i].ep); |
618 | err = USBD_INVAL; | | 618 | err = USBD_INVAL; |
619 | goto error; | | 619 | goto error; |
620 | } | | 620 | } |
621 | if (UE_GET_XFERTYPE(epd->bmAttributes)!=UE_BULK || | | 621 | if (UE_GET_XFERTYPE(epd->bmAttributes)!=UE_BULK || |
622 | UE_GET_DIR(epd->bEndpointAddress)!=UE_DIR_OUT) { | | 622 | UE_GET_DIR(epd->bEndpointAddress)!=UE_DIR_OUT) { |
623 | aprint_error_dev(sc->sc_dev, "illegal endpoint(out:%d)\n", | | 623 | aprint_error_dev(sc->sc_dev, "illegal endpoint(out:%d)\n", |
624 | fp->out_ep[i].ep); | | 624 | fp->out_ep[i].ep); |
625 | err = USBD_INVAL; | | 625 | err = USBD_INVAL; |
626 | goto error; | | 626 | goto error; |
627 | } | | 627 | } |
628 | ep->sc = sc; | | 628 | ep->sc = sc; |
629 | ep->addr = epd->bEndpointAddress; | | 629 | ep->addr = epd->bEndpointAddress; |
630 | ep->num_jacks = fp->out_ep[i].num_jacks; | | 630 | ep->num_jacks = fp->out_ep[i].num_jacks; |
631 | sc->sc_out_num_jacks += fp->out_ep[i].num_jacks; | | 631 | sc->sc_out_num_jacks += fp->out_ep[i].num_jacks; |
632 | ep->num_open = 0; | | 632 | ep->num_open = 0; |
633 | ep++; | | 633 | ep++; |
634 | } | | 634 | } |
635 | ep = &sc->sc_in_ep[0]; | | 635 | ep = &sc->sc_in_ep[0]; |
636 | for (i = 0; i < sc->sc_in_num_endpoints; i++) { | | 636 | for (i = 0; i < sc->sc_in_num_endpoints; i++) { |
637 | epd = usbd_interface2endpoint_descriptor( | | 637 | epd = usbd_interface2endpoint_descriptor( |
638 | sc->sc_iface, | | 638 | sc->sc_iface, |
639 | fp->in_ep[i].ep); | | 639 | fp->in_ep[i].ep); |
640 | if (!epd) { | | 640 | if (!epd) { |
641 | aprint_error_dev(sc->sc_dev, | | 641 | aprint_error_dev(sc->sc_dev, |
642 | "cannot get endpoint descriptor(in:%d)\n", | | 642 | "cannot get endpoint descriptor(in:%d)\n", |
643 | fp->in_ep[i].ep); | | 643 | fp->in_ep[i].ep); |
644 | err = USBD_INVAL; | | 644 | err = USBD_INVAL; |
645 | goto error; | | 645 | goto error; |
646 | } | | 646 | } |
647 | /* | | 647 | /* |
648 | * MIDISPORT_2X4 inputs on an interrupt rather than a bulk | | 648 | * MIDISPORT_2X4 inputs on an interrupt rather than a bulk |
649 | * endpoint. The existing input logic in this driver seems | | 649 | * endpoint. The existing input logic in this driver seems |
650 | * to work successfully if we just stop treating an interrupt | | 650 | * to work successfully if we just stop treating an interrupt |
651 | * endpoint as illegal (or the in_progress status we get on | | 651 | * endpoint as illegal (or the in_progress status we get on |
652 | * the initial transfer). It does not seem necessary to | | 652 | * the initial transfer). It does not seem necessary to |
653 | * actually use the interrupt flavor of alloc_pipe or make | | 653 | * actually use the interrupt flavor of alloc_pipe or make |
654 | * other serious rearrangements of logic. I like that. | | 654 | * other serious rearrangements of logic. I like that. |
655 | */ | | 655 | */ |
656 | switch ( UE_GET_XFERTYPE(epd->bmAttributes) ) { | | 656 | switch ( UE_GET_XFERTYPE(epd->bmAttributes) ) { |
657 | case UE_BULK: | | 657 | case UE_BULK: |
658 | case UE_INTERRUPT: | | 658 | case UE_INTERRUPT: |
659 | if ( UE_DIR_IN == UE_GET_DIR(epd->bEndpointAddress) ) | | 659 | if ( UE_DIR_IN == UE_GET_DIR(epd->bEndpointAddress) ) |
660 | break; | | 660 | break; |
661 | /*FALLTHROUGH*/ | | 661 | /*FALLTHROUGH*/ |
662 | default: | | 662 | default: |
663 | aprint_error_dev(sc->sc_dev, | | 663 | aprint_error_dev(sc->sc_dev, |
664 | "illegal endpoint(in:%d)\n", fp->in_ep[i].ep); | | 664 | "illegal endpoint(in:%d)\n", fp->in_ep[i].ep); |
665 | err = USBD_INVAL; | | 665 | err = USBD_INVAL; |
666 | goto error; | | 666 | goto error; |
667 | } | | 667 | } |
668 | | | 668 | |
669 | ep->sc = sc; | | 669 | ep->sc = sc; |
670 | ep->addr = epd->bEndpointAddress; | | 670 | ep->addr = epd->bEndpointAddress; |
671 | ep->num_jacks = fp->in_ep[i].num_jacks; | | 671 | ep->num_jacks = fp->in_ep[i].num_jacks; |
672 | sc->sc_in_num_jacks += fp->in_ep[i].num_jacks; | | 672 | sc->sc_in_num_jacks += fp->in_ep[i].num_jacks; |
673 | ep->num_open = 0; | | 673 | ep->num_open = 0; |
674 | ep++; | | 674 | ep++; |
675 | } | | 675 | } |
676 | | | 676 | |
677 | return USBD_NORMAL_COMPLETION; | | 677 | return USBD_NORMAL_COMPLETION; |
678 | error: | | 678 | error: |
679 | kmem_free(sc->sc_endpoints, UMIDI_ENDPOINT_SIZE(sc)); | | 679 | kmem_free(sc->sc_endpoints, UMIDI_ENDPOINT_SIZE(sc)); |
680 | sc->sc_endpoints = NULL; | | 680 | sc->sc_endpoints = NULL; |
681 | return err; | | 681 | return err; |
682 | } | | 682 | } |
683 | | | 683 | |
684 | static usbd_status | | 684 | static usbd_status |
685 | alloc_all_endpoints_yamaha(struct umidi_softc *sc) | | 685 | alloc_all_endpoints_yamaha(struct umidi_softc *sc) |
686 | { | | 686 | { |
687 | /* This driver currently supports max 1in/1out bulk endpoints */ | | 687 | /* This driver currently supports max 1in/1out bulk endpoints */ |
688 | usb_descriptor_t *desc; | | 688 | usb_descriptor_t *desc; |
689 | umidi_cs_descriptor_t *udesc; | | 689 | umidi_cs_descriptor_t *udesc; |
690 | usb_endpoint_descriptor_t *epd; | | 690 | usb_endpoint_descriptor_t *epd; |
691 | int out_addr, in_addr, i; | | 691 | int out_addr, in_addr, i; |
692 | int dir; | | 692 | int dir; |
693 | size_t remain, descsize; | | 693 | size_t remain, descsize; |
694 | | | 694 | |
695 | sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0; | | 695 | sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0; |
696 | out_addr = in_addr = 0; | | 696 | out_addr = in_addr = 0; |
697 | | | 697 | |
698 | /* detect endpoints */ | | 698 | /* detect endpoints */ |
699 | desc = TO_D(usbd_get_interface_descriptor(sc->sc_iface)); | | 699 | desc = TO_D(usbd_get_interface_descriptor(sc->sc_iface)); |
700 | for (i=(int)TO_IFD(desc)->bNumEndpoints-1; i>=0; i--) { | | 700 | for (i=(int)TO_IFD(desc)->bNumEndpoints-1; i>=0; i--) { |
701 | epd = usbd_interface2endpoint_descriptor(sc->sc_iface, i); | | 701 | epd = usbd_interface2endpoint_descriptor(sc->sc_iface, i); |
702 | KASSERT(epd != NULL); | | 702 | KASSERT(epd != NULL); |
703 | if (UE_GET_XFERTYPE(epd->bmAttributes) == UE_BULK) { | | 703 | if (UE_GET_XFERTYPE(epd->bmAttributes) == UE_BULK) { |
704 | dir = UE_GET_DIR(epd->bEndpointAddress); | | 704 | dir = UE_GET_DIR(epd->bEndpointAddress); |
705 | if (dir==UE_DIR_OUT && !out_addr) | | 705 | if (dir==UE_DIR_OUT && !out_addr) |
706 | out_addr = epd->bEndpointAddress; | | 706 | out_addr = epd->bEndpointAddress; |
707 | else if (dir==UE_DIR_IN && !in_addr) | | 707 | else if (dir==UE_DIR_IN && !in_addr) |
708 | in_addr = epd->bEndpointAddress; | | 708 | in_addr = epd->bEndpointAddress; |
709 | } | | 709 | } |
710 | } | | 710 | } |
711 | udesc = (umidi_cs_descriptor_t *)NEXT_D(desc); | | 711 | udesc = (umidi_cs_descriptor_t *)NEXT_D(desc); |
712 | | | 712 | |
713 | /* count jacks */ | | 713 | /* count jacks */ |
714 | if (!(udesc->bDescriptorType==UDESC_CS_INTERFACE && | | 714 | if (!(udesc->bDescriptorType==UDESC_CS_INTERFACE && |
715 | udesc->bDescriptorSubtype==UMIDI_MS_HEADER)) | | 715 | udesc->bDescriptorSubtype==UMIDI_MS_HEADER)) |
716 | return USBD_INVAL; | | 716 | return USBD_INVAL; |
717 | remain = (size_t)UGETW(TO_CSIFD(udesc)->wTotalLength) - | | 717 | remain = (size_t)UGETW(TO_CSIFD(udesc)->wTotalLength) - |
718 | (size_t)udesc->bLength; | | 718 | (size_t)udesc->bLength; |
719 | udesc = (umidi_cs_descriptor_t *)NEXT_D(udesc); | | 719 | udesc = (umidi_cs_descriptor_t *)NEXT_D(udesc); |
720 | | | 720 | |
721 | while (remain >= sizeof(usb_descriptor_t)) { | | 721 | while (remain >= sizeof(usb_descriptor_t)) { |
722 | descsize = udesc->bLength; | | 722 | descsize = udesc->bLength; |
723 | if (descsize>remain || descsize==0) | | 723 | if (descsize>remain || descsize==0) |
724 | break; | | 724 | break; |
725 | if (udesc->bDescriptorType == UDESC_CS_INTERFACE && | | 725 | if (udesc->bDescriptorType == UDESC_CS_INTERFACE && |
726 | remain >= UMIDI_JACK_DESCRIPTOR_SIZE) { | | 726 | remain >= UMIDI_JACK_DESCRIPTOR_SIZE) { |
727 | if (udesc->bDescriptorSubtype == UMIDI_OUT_JACK) | | 727 | if (udesc->bDescriptorSubtype == UMIDI_OUT_JACK) |
728 | sc->sc_out_num_jacks++; | | 728 | sc->sc_out_num_jacks++; |
729 | else if (udesc->bDescriptorSubtype == UMIDI_IN_JACK) | | 729 | else if (udesc->bDescriptorSubtype == UMIDI_IN_JACK) |
730 | sc->sc_in_num_jacks++; | | 730 | sc->sc_in_num_jacks++; |
731 | } | | 731 | } |
732 | udesc = (umidi_cs_descriptor_t *)NEXT_D(udesc); | | 732 | udesc = (umidi_cs_descriptor_t *)NEXT_D(udesc); |
733 | remain -= descsize; | | 733 | remain -= descsize; |
734 | } | | 734 | } |
735 | | | 735 | |
736 | /* validate some parameters */ | | 736 | /* validate some parameters */ |
737 | if (sc->sc_out_num_jacks>UMIDI_MAX_EPJACKS) | | 737 | if (sc->sc_out_num_jacks>UMIDI_MAX_EPJACKS) |
738 | sc->sc_out_num_jacks = UMIDI_MAX_EPJACKS; | | 738 | sc->sc_out_num_jacks = UMIDI_MAX_EPJACKS; |
739 | if (sc->sc_in_num_jacks>UMIDI_MAX_EPJACKS) | | 739 | if (sc->sc_in_num_jacks>UMIDI_MAX_EPJACKS) |
740 | sc->sc_in_num_jacks = UMIDI_MAX_EPJACKS; | | 740 | sc->sc_in_num_jacks = UMIDI_MAX_EPJACKS; |
741 | if (sc->sc_out_num_jacks && out_addr) { | | 741 | if (sc->sc_out_num_jacks && out_addr) { |
742 | sc->sc_out_num_endpoints = 1; | | 742 | sc->sc_out_num_endpoints = 1; |
743 | } else { | | 743 | } else { |
744 | sc->sc_out_num_endpoints = 0; | | 744 | sc->sc_out_num_endpoints = 0; |
745 | sc->sc_out_num_jacks = 0; | | 745 | sc->sc_out_num_jacks = 0; |
746 | } | | 746 | } |
747 | if (sc->sc_in_num_jacks && in_addr) { | | 747 | if (sc->sc_in_num_jacks && in_addr) { |
748 | sc->sc_in_num_endpoints = 1; | | 748 | sc->sc_in_num_endpoints = 1; |
749 | } else { | | 749 | } else { |
750 | sc->sc_in_num_endpoints = 0; | | 750 | sc->sc_in_num_endpoints = 0; |
751 | sc->sc_in_num_jacks = 0; | | 751 | sc->sc_in_num_jacks = 0; |
752 | } | | 752 | } |
753 | sc->sc_endpoints_len = UMIDI_ENDPOINT_SIZE(sc); | | 753 | sc->sc_endpoints_len = UMIDI_ENDPOINT_SIZE(sc); |
754 | sc->sc_endpoints = kmem_zalloc(sc->sc_endpoints_len, KM_SLEEP); | | 754 | sc->sc_endpoints = kmem_zalloc(sc->sc_endpoints_len, KM_SLEEP); |
755 | if (!sc->sc_endpoints) | | 755 | if (!sc->sc_endpoints) |
756 | return USBD_NOMEM; | | 756 | return USBD_NOMEM; |
757 | if (sc->sc_out_num_endpoints) { | | 757 | if (sc->sc_out_num_endpoints) { |
758 | sc->sc_out_ep = sc->sc_endpoints; | | 758 | sc->sc_out_ep = sc->sc_endpoints; |
759 | sc->sc_out_ep->sc = sc; | | 759 | sc->sc_out_ep->sc = sc; |
760 | sc->sc_out_ep->addr = out_addr; | | 760 | sc->sc_out_ep->addr = out_addr; |
761 | sc->sc_out_ep->num_jacks = sc->sc_out_num_jacks; | | 761 | sc->sc_out_ep->num_jacks = sc->sc_out_num_jacks; |
762 | sc->sc_out_ep->num_open = 0; | | 762 | sc->sc_out_ep->num_open = 0; |
763 | } else | | 763 | } else |
764 | sc->sc_out_ep = NULL; | | 764 | sc->sc_out_ep = NULL; |
765 | | | 765 | |
766 | if (sc->sc_in_num_endpoints) { | | 766 | if (sc->sc_in_num_endpoints) { |
767 | sc->sc_in_ep = sc->sc_endpoints+sc->sc_out_num_endpoints; | | 767 | sc->sc_in_ep = sc->sc_endpoints+sc->sc_out_num_endpoints; |
768 | sc->sc_in_ep->sc = sc; | | 768 | sc->sc_in_ep->sc = sc; |
769 | sc->sc_in_ep->addr = in_addr; | | 769 | sc->sc_in_ep->addr = in_addr; |
770 | sc->sc_in_ep->num_jacks = sc->sc_in_num_jacks; | | 770 | sc->sc_in_ep->num_jacks = sc->sc_in_num_jacks; |
771 | sc->sc_in_ep->num_open = 0; | | 771 | sc->sc_in_ep->num_open = 0; |
772 | } else | | 772 | } else |
773 | sc->sc_in_ep = NULL; | | 773 | sc->sc_in_ep = NULL; |
774 | | | 774 | |
775 | return USBD_NORMAL_COMPLETION; | | 775 | return USBD_NORMAL_COMPLETION; |
776 | } | | 776 | } |
777 | | | 777 | |
778 | static usbd_status | | 778 | static usbd_status |
779 | alloc_all_endpoints_genuine(struct umidi_softc *sc) | | 779 | alloc_all_endpoints_genuine(struct umidi_softc *sc) |
780 | { | | 780 | { |
781 | usb_interface_descriptor_t *interface_desc; | | 781 | usb_interface_descriptor_t *interface_desc; |
782 | usb_config_descriptor_t *config_desc; | | 782 | usb_config_descriptor_t *config_desc; |
783 | usb_descriptor_t *desc; | | 783 | usb_descriptor_t *desc; |
784 | int num_ep; | | 784 | int num_ep; |
785 | size_t remain, descsize; | | 785 | size_t remain, descsize; |
786 | struct umidi_endpoint *p, *q, *lowest, *endep, tmpep; | | 786 | struct umidi_endpoint *p, *q, *lowest, *endep, tmpep; |
787 | int epaddr; | | 787 | int epaddr; |
788 | | | 788 | |
789 | interface_desc = usbd_get_interface_descriptor(sc->sc_iface); | | 789 | interface_desc = usbd_get_interface_descriptor(sc->sc_iface); |
790 | num_ep = interface_desc->bNumEndpoints; | | 790 | num_ep = interface_desc->bNumEndpoints; |
791 | sc->sc_endpoints_len = sizeof(struct umidi_endpoint) * num_ep; | | 791 | sc->sc_endpoints_len = sizeof(struct umidi_endpoint) * num_ep; |
792 | sc->sc_endpoints = p = kmem_zalloc(sc->sc_endpoints_len, KM_SLEEP); | | 792 | sc->sc_endpoints = p = kmem_zalloc(sc->sc_endpoints_len, KM_SLEEP); |
793 | if (!p) | | 793 | if (!p) |
794 | return USBD_NOMEM; | | 794 | return USBD_NOMEM; |
795 | | | 795 | |
796 | sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0; | | 796 | sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0; |
797 | sc->sc_out_num_endpoints = sc->sc_in_num_endpoints = 0; | | 797 | sc->sc_out_num_endpoints = sc->sc_in_num_endpoints = 0; |
798 | epaddr = -1; | | 798 | epaddr = -1; |
799 | | | 799 | |
800 | /* get the list of endpoints for midi stream */ | | 800 | /* get the list of endpoints for midi stream */ |
801 | config_desc = usbd_get_config_descriptor(sc->sc_udev); | | 801 | config_desc = usbd_get_config_descriptor(sc->sc_udev); |
802 | desc = (usb_descriptor_t *) config_desc; | | 802 | desc = (usb_descriptor_t *) config_desc; |
803 | remain = (size_t)UGETW(config_desc->wTotalLength); | | 803 | remain = (size_t)UGETW(config_desc->wTotalLength); |
804 | while (remain>=sizeof(usb_descriptor_t)) { | | 804 | while (remain>=sizeof(usb_descriptor_t)) { |
805 | descsize = desc->bLength; | | 805 | descsize = desc->bLength; |
806 | if (descsize>remain || descsize==0) | | 806 | if (descsize>remain || descsize==0) |
807 | break; | | 807 | break; |
808 | if (desc->bDescriptorType==UDESC_ENDPOINT && | | 808 | if (desc->bDescriptorType==UDESC_ENDPOINT && |
809 | remain>=USB_ENDPOINT_DESCRIPTOR_SIZE && | | 809 | remain>=USB_ENDPOINT_DESCRIPTOR_SIZE && |
810 | UE_GET_XFERTYPE(TO_EPD(desc)->bmAttributes) == UE_BULK) { | | 810 | UE_GET_XFERTYPE(TO_EPD(desc)->bmAttributes) == UE_BULK) { |
811 | epaddr = TO_EPD(desc)->bEndpointAddress; | | 811 | epaddr = TO_EPD(desc)->bEndpointAddress; |
812 | } else if (desc->bDescriptorType==UDESC_CS_ENDPOINT && | | 812 | } else if (desc->bDescriptorType==UDESC_CS_ENDPOINT && |
813 | remain>=UMIDI_CS_ENDPOINT_DESCRIPTOR_SIZE && | | 813 | remain>=UMIDI_CS_ENDPOINT_DESCRIPTOR_SIZE && |
814 | epaddr!=-1) { | | 814 | epaddr!=-1) { |
815 | if (num_ep>0) { | | 815 | if (num_ep>0) { |
816 | num_ep--; | | 816 | num_ep--; |
817 | p->sc = sc; | | 817 | p->sc = sc; |
818 | p->addr = epaddr; | | 818 | p->addr = epaddr; |
819 | p->num_jacks = TO_CSEPD(desc)->bNumEmbMIDIJack; | | 819 | p->num_jacks = TO_CSEPD(desc)->bNumEmbMIDIJack; |
820 | if (UE_GET_DIR(epaddr)==UE_DIR_OUT) { | | 820 | if (UE_GET_DIR(epaddr)==UE_DIR_OUT) { |
821 | sc->sc_out_num_endpoints++; | | 821 | sc->sc_out_num_endpoints++; |
822 | sc->sc_out_num_jacks += p->num_jacks; | | 822 | sc->sc_out_num_jacks += p->num_jacks; |
823 | } else { | | 823 | } else { |
824 | sc->sc_in_num_endpoints++; | | 824 | sc->sc_in_num_endpoints++; |
825 | sc->sc_in_num_jacks += p->num_jacks; | | 825 | sc->sc_in_num_jacks += p->num_jacks; |
826 | } | | 826 | } |
827 | p++; | | 827 | p++; |
828 | } | | 828 | } |
829 | } else | | 829 | } else |
830 | epaddr = -1; | | 830 | epaddr = -1; |
831 | desc = NEXT_D(desc); | | 831 | desc = NEXT_D(desc); |
832 | remain-=descsize; | | 832 | remain-=descsize; |
833 | } | | 833 | } |
834 | | | 834 | |
835 | /* sort endpoints */ | | 835 | /* sort endpoints */ |
836 | num_ep = sc->sc_out_num_endpoints + sc->sc_in_num_endpoints; | | 836 | num_ep = sc->sc_out_num_endpoints + sc->sc_in_num_endpoints; |
837 | p = sc->sc_endpoints; | | 837 | p = sc->sc_endpoints; |
838 | endep = p + num_ep; | | 838 | endep = p + num_ep; |
839 | while (p<endep) { | | 839 | while (p<endep) { |
840 | lowest = p; | | 840 | lowest = p; |
841 | for (q=p+1; q<endep; q++) { | | 841 | for (q=p+1; q<endep; q++) { |
842 | if ((UE_GET_DIR(lowest->addr)==UE_DIR_IN && | | 842 | if ((UE_GET_DIR(lowest->addr)==UE_DIR_IN && |
843 | UE_GET_DIR(q->addr)==UE_DIR_OUT) || | | 843 | UE_GET_DIR(q->addr)==UE_DIR_OUT) || |
844 | ((UE_GET_DIR(lowest->addr)== | | 844 | ((UE_GET_DIR(lowest->addr)== |
845 | UE_GET_DIR(q->addr)) && | | 845 | UE_GET_DIR(q->addr)) && |
846 | (UE_GET_ADDR(lowest->addr)> | | 846 | (UE_GET_ADDR(lowest->addr)> |
847 | UE_GET_ADDR(q->addr)))) | | 847 | UE_GET_ADDR(q->addr)))) |
848 | lowest = q; | | 848 | lowest = q; |
849 | } | | 849 | } |
850 | if (lowest != p) { | | 850 | if (lowest != p) { |
851 | memcpy((void *)&tmpep, (void *)p, sizeof(tmpep)); | | 851 | memcpy((void *)&tmpep, (void *)p, sizeof(tmpep)); |
852 | memcpy((void *)p, (void *)lowest, sizeof(tmpep)); | | 852 | memcpy((void *)p, (void *)lowest, sizeof(tmpep)); |
853 | memcpy((void *)lowest, (void *)&tmpep, sizeof(tmpep)); | | 853 | memcpy((void *)lowest, (void *)&tmpep, sizeof(tmpep)); |
854 | } | | 854 | } |
855 | p->num_open = 0; | | 855 | p->num_open = 0; |
856 | p++; | | 856 | p++; |
857 | } | | 857 | } |
858 | | | 858 | |
859 | sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL; | | 859 | sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL; |
860 | sc->sc_in_ep = | | 860 | sc->sc_in_ep = |
861 | sc->sc_in_num_endpoints ? | | 861 | sc->sc_in_num_endpoints ? |
862 | sc->sc_endpoints+sc->sc_out_num_endpoints : NULL; | | 862 | sc->sc_endpoints+sc->sc_out_num_endpoints : NULL; |
863 | | | 863 | |
864 | return USBD_NORMAL_COMPLETION; | | 864 | return USBD_NORMAL_COMPLETION; |
865 | } | | 865 | } |
866 | | | 866 | |
867 | | | 867 | |
868 | /* | | 868 | /* |
869 | * jack stuffs | | 869 | * jack stuffs |
870 | */ | | 870 | */ |
871 | | | 871 | |
872 | static usbd_status | | 872 | static usbd_status |
873 | alloc_all_jacks(struct umidi_softc *sc) | | 873 | alloc_all_jacks(struct umidi_softc *sc) |
874 | { | | 874 | { |
875 | int i, j; | | 875 | int i, j; |
876 | struct umidi_endpoint *ep; | | 876 | struct umidi_endpoint *ep; |
877 | struct umidi_jack *jack; | | 877 | struct umidi_jack *jack; |
878 | const unsigned char *cn_spec; | | 878 | const unsigned char *cn_spec; |
879 | | | 879 | |
880 | if (UMQ_ISTYPE(sc, UMQ_TYPE_CN_SEQ_PER_EP)) | | 880 | if (UMQ_ISTYPE(sc, UMQ_TYPE_CN_SEQ_PER_EP)) |
881 | sc->cblnums_global = 0; | | 881 | sc->cblnums_global = 0; |
882 | else if (UMQ_ISTYPE(sc, UMQ_TYPE_CN_SEQ_GLOBAL)) | | 882 | else if (UMQ_ISTYPE(sc, UMQ_TYPE_CN_SEQ_GLOBAL)) |
883 | sc->cblnums_global = 1; | | 883 | sc->cblnums_global = 1; |
884 | else { | | 884 | else { |
885 | /* | | 885 | /* |
886 | * I don't think this default is correct, but it preserves | | 886 | * I don't think this default is correct, but it preserves |
887 | * the prior behavior of the code. That's why I defined two | | 887 | * the prior behavior of the code. That's why I defined two |
888 | * complementary quirks. Any device for which the default | | 888 | * complementary quirks. Any device for which the default |
889 | * behavior is wrong can be made to work by giving it an | | 889 | * behavior is wrong can be made to work by giving it an |
890 | * explicit quirk, and if a pattern ever develops (as I suspect | | 890 | * explicit quirk, and if a pattern ever develops (as I suspect |
891 | * it will) that a lot of otherwise standard USB MIDI devices | | 891 | * it will) that a lot of otherwise standard USB MIDI devices |
892 | * need the CN_SEQ_PER_EP "quirk," then this default can be | | 892 | * need the CN_SEQ_PER_EP "quirk," then this default can be |
893 | * changed to 0, and the only devices that will break are those | | 893 | * changed to 0, and the only devices that will break are those |
894 | * listing neither quirk, and they'll easily be fixed by giving | | 894 | * listing neither quirk, and they'll easily be fixed by giving |
895 | * them the CN_SEQ_GLOBAL quirk. | | 895 | * them the CN_SEQ_GLOBAL quirk. |
896 | */ | | 896 | */ |
897 | sc->cblnums_global = 1; | | 897 | sc->cblnums_global = 1; |
898 | } | | 898 | } |
899 | | | 899 | |
900 | if (UMQ_ISTYPE(sc, UMQ_TYPE_CN_FIXED)) | | 900 | if (UMQ_ISTYPE(sc, UMQ_TYPE_CN_FIXED)) |
901 | cn_spec = umidi_get_quirk_data_from_type(sc->sc_quirk, | | 901 | cn_spec = umidi_get_quirk_data_from_type(sc->sc_quirk, |
902 | UMQ_TYPE_CN_FIXED); | | 902 | UMQ_TYPE_CN_FIXED); |
903 | else | | 903 | else |
904 | cn_spec = NULL; | | 904 | cn_spec = NULL; |
905 | | | 905 | |
906 | /* allocate/initialize structures */ | | 906 | /* allocate/initialize structures */ |
907 | sc->sc_jacks = kmem_zalloc(sizeof(*sc->sc_out_jacks)*(sc->sc_in_num_jacks+ | | 907 | sc->sc_jacks = kmem_zalloc(sizeof(*sc->sc_out_jacks)*(sc->sc_in_num_jacks+ |
908 | sc->sc_out_num_jacks), KM_SLEEP); | | 908 | sc->sc_out_num_jacks), KM_SLEEP); |
909 | if (!sc->sc_jacks) | | 909 | if (!sc->sc_jacks) |
910 | return USBD_NOMEM; | | 910 | return USBD_NOMEM; |
911 | sc->sc_out_jacks = | | 911 | sc->sc_out_jacks = |
912 | sc->sc_out_num_jacks ? sc->sc_jacks : NULL; | | 912 | sc->sc_out_num_jacks ? sc->sc_jacks : NULL; |
913 | sc->sc_in_jacks = | | 913 | sc->sc_in_jacks = |
914 | sc->sc_in_num_jacks ? sc->sc_jacks+sc->sc_out_num_jacks : NULL; | | 914 | sc->sc_in_num_jacks ? sc->sc_jacks+sc->sc_out_num_jacks : NULL; |
915 | | | 915 | |
916 | jack = &sc->sc_out_jacks[0]; | | 916 | jack = &sc->sc_out_jacks[0]; |
917 | for (i = 0; i < sc->sc_out_num_jacks; i++) { | | 917 | for (i = 0; i < sc->sc_out_num_jacks; i++) { |
918 | jack->opened = 0; | | 918 | jack->opened = 0; |
919 | jack->binded = 0; | | 919 | jack->binded = 0; |
920 | jack->arg = NULL; | | 920 | jack->arg = NULL; |
921 | jack->u.out.intr = NULL; | | 921 | jack->u.out.intr = NULL; |
922 | jack->midiman_ppkt = NULL; | | 922 | jack->midiman_ppkt = NULL; |
923 | if (sc->cblnums_global) | | 923 | if (sc->cblnums_global) |
924 | jack->cable_number = i; | | 924 | jack->cable_number = i; |
925 | jack++; | | 925 | jack++; |
926 | } | | 926 | } |
927 | jack = &sc->sc_in_jacks[0]; | | 927 | jack = &sc->sc_in_jacks[0]; |
928 | for (i = 0; i < sc->sc_in_num_jacks; i++) { | | 928 | for (i = 0; i < sc->sc_in_num_jacks; i++) { |
929 | jack->opened = 0; | | 929 | jack->opened = 0; |
930 | jack->binded = 0; | | 930 | jack->binded = 0; |
931 | jack->arg = NULL; | | 931 | jack->arg = NULL; |
932 | jack->u.in.intr = NULL; | | 932 | jack->u.in.intr = NULL; |
933 | if (sc->cblnums_global) | | 933 | if (sc->cblnums_global) |
934 | jack->cable_number = i; | | 934 | jack->cable_number = i; |
935 | jack++; | | 935 | jack++; |
936 | } | | 936 | } |
937 | | | 937 | |
938 | /* assign each jacks to each endpoints */ | | 938 | /* assign each jacks to each endpoints */ |
939 | jack = &sc->sc_out_jacks[0]; | | 939 | jack = &sc->sc_out_jacks[0]; |
940 | ep = &sc->sc_out_ep[0]; | | 940 | ep = &sc->sc_out_ep[0]; |
941 | for (i = 0; i < sc->sc_out_num_endpoints; i++) { | | 941 | for (i = 0; i < sc->sc_out_num_endpoints; i++) { |
942 | for (j = 0; j < ep->num_jacks; j++) { | | 942 | for (j = 0; j < ep->num_jacks; j++) { |
943 | jack->endpoint = ep; | | 943 | jack->endpoint = ep; |
944 | if (cn_spec != NULL) | | 944 | if (cn_spec != NULL) |
945 | jack->cable_number = *cn_spec++; | | 945 | jack->cable_number = *cn_spec++; |
946 | else if (!sc->cblnums_global) | | 946 | else if (!sc->cblnums_global) |
947 | jack->cable_number = j; | | 947 | jack->cable_number = j; |
948 | ep->jacks[jack->cable_number] = jack; | | 948 | ep->jacks[jack->cable_number] = jack; |
949 | jack++; | | 949 | jack++; |
950 | } | | 950 | } |
951 | ep++; | | 951 | ep++; |
952 | } | | 952 | } |
953 | jack = &sc->sc_in_jacks[0]; | | 953 | jack = &sc->sc_in_jacks[0]; |
954 | ep = &sc->sc_in_ep[0]; | | 954 | ep = &sc->sc_in_ep[0]; |
955 | for (i = 0; i < sc->sc_in_num_endpoints; i++) { | | 955 | for (i = 0; i < sc->sc_in_num_endpoints; i++) { |
956 | for (j = 0; j < ep->num_jacks; j++) { | | 956 | for (j = 0; j < ep->num_jacks; j++) { |
957 | jack->endpoint = ep; | | 957 | jack->endpoint = ep; |
958 | if (cn_spec != NULL) | | 958 | if (cn_spec != NULL) |
959 | jack->cable_number = *cn_spec++; | | 959 | jack->cable_number = *cn_spec++; |
960 | else if (!sc->cblnums_global) | | 960 | else if (!sc->cblnums_global) |
961 | jack->cable_number = j; | | 961 | jack->cable_number = j; |
962 | ep->jacks[jack->cable_number] = jack; | | 962 | ep->jacks[jack->cable_number] = jack; |
963 | jack++; | | 963 | jack++; |
964 | } | | 964 | } |
965 | ep++; | | 965 | ep++; |
966 | } | | 966 | } |
967 | | | 967 | |
968 | return USBD_NORMAL_COMPLETION; | | 968 | return USBD_NORMAL_COMPLETION; |
969 | } | | 969 | } |
970 | | | 970 | |
971 | static void | | 971 | static void |
972 | free_all_jacks(struct umidi_softc *sc) | | 972 | free_all_jacks(struct umidi_softc *sc) |
973 | { | | 973 | { |
974 | struct umidi_jack *jacks; | | 974 | struct umidi_jack *jacks; |
975 | size_t len; | | 975 | size_t len; |
976 | | | 976 | |
977 | mutex_enter(&sc->sc_lock); | | 977 | mutex_enter(&sc->sc_lock); |
978 | jacks = sc->sc_jacks; | | 978 | jacks = sc->sc_jacks; |
979 | len = sizeof(*sc->sc_out_jacks)*(sc->sc_in_num_jacks+sc->sc_out_num_jacks); | | 979 | len = sizeof(*sc->sc_out_jacks)*(sc->sc_in_num_jacks+sc->sc_out_num_jacks); |
980 | sc->sc_jacks = sc->sc_in_jacks = sc->sc_out_jacks = NULL; | | 980 | sc->sc_jacks = sc->sc_in_jacks = sc->sc_out_jacks = NULL; |
981 | mutex_exit(&sc->sc_lock); | | 981 | mutex_exit(&sc->sc_lock); |
982 | | | 982 | |
983 | if (jacks) | | 983 | if (jacks) |
984 | kmem_free(jacks, len); | | 984 | kmem_free(jacks, len); |
985 | } | | 985 | } |
986 | | | 986 | |
987 | static usbd_status | | 987 | static usbd_status |
988 | bind_jacks_to_mididev(struct umidi_softc *sc, | | 988 | bind_jacks_to_mididev(struct umidi_softc *sc, |
989 | struct umidi_jack *out_jack, | | 989 | struct umidi_jack *out_jack, |
990 | struct umidi_jack *in_jack, | | 990 | struct umidi_jack *in_jack, |
991 | struct umidi_mididev *mididev) | | 991 | struct umidi_mididev *mididev) |
992 | { | | 992 | { |
993 | if ((out_jack && out_jack->binded) || (in_jack && in_jack->binded)) | | 993 | if ((out_jack && out_jack->binded) || (in_jack && in_jack->binded)) |
994 | return USBD_IN_USE; | | 994 | return USBD_IN_USE; |
995 | if (mididev->out_jack || mididev->in_jack) | | 995 | if (mididev->out_jack || mididev->in_jack) |
996 | return USBD_IN_USE; | | 996 | return USBD_IN_USE; |
997 | | | 997 | |
998 | if (out_jack) | | 998 | if (out_jack) |
999 | out_jack->binded = 1; | | 999 | out_jack->binded = 1; |
1000 | if (in_jack) | | 1000 | if (in_jack) |
1001 | in_jack->binded = 1; | | 1001 | in_jack->binded = 1; |
1002 | mididev->in_jack = in_jack; | | 1002 | mididev->in_jack = in_jack; |
1003 | mididev->out_jack = out_jack; | | 1003 | mididev->out_jack = out_jack; |
1004 | | | 1004 | |
1005 | return USBD_NORMAL_COMPLETION; | | 1005 | return USBD_NORMAL_COMPLETION; |
1006 | } | | 1006 | } |
1007 | | | 1007 | |
1008 | static void | | 1008 | static void |
1009 | unbind_jacks_from_mididev(struct umidi_mididev *mididev) | | 1009 | unbind_jacks_from_mididev(struct umidi_mididev *mididev) |
1010 | { | | 1010 | { |
1011 | | | 1011 | |
1012 | if ((mididev->flags & FWRITE) && mididev->out_jack) | | 1012 | if ((mididev->flags & FWRITE) && mididev->out_jack) |
1013 | close_out_jack(mididev->out_jack); | | 1013 | close_out_jack(mididev->out_jack); |
1014 | if ((mididev->flags & FREAD) && mididev->in_jack) | | 1014 | if ((mididev->flags & FREAD) && mididev->in_jack) |
1015 | close_in_jack(mididev->in_jack); | | 1015 | close_in_jack(mididev->in_jack); |
1016 | | | 1016 | |
1017 | if (mididev->out_jack) | | 1017 | if (mididev->out_jack) |
1018 | mididev->out_jack->binded = 0; | | 1018 | mididev->out_jack->binded = 0; |
1019 | if (mididev->in_jack) | | 1019 | if (mididev->in_jack) |
1020 | mididev->in_jack->binded = 0; | | 1020 | mididev->in_jack->binded = 0; |
1021 | mididev->out_jack = mididev->in_jack = NULL; | | 1021 | mididev->out_jack = mididev->in_jack = NULL; |
1022 | } | | 1022 | } |
1023 | | | 1023 | |
1024 | static void | | 1024 | static void |
1025 | unbind_all_jacks(struct umidi_softc *sc) | | 1025 | unbind_all_jacks(struct umidi_softc *sc) |
1026 | { | | 1026 | { |
1027 | int i; | | 1027 | int i; |
1028 | | | 1028 | |
1029 | if (sc->sc_mididevs) | | 1029 | if (sc->sc_mididevs) |
1030 | for (i = 0; i < sc->sc_num_mididevs; i++) | | 1030 | for (i = 0; i < sc->sc_num_mididevs; i++) |
1031 | unbind_jacks_from_mididev(&sc->sc_mididevs[i]); | | 1031 | unbind_jacks_from_mididev(&sc->sc_mididevs[i]); |
1032 | } | | 1032 | } |
1033 | | | 1033 | |
1034 | static usbd_status | | 1034 | static usbd_status |
1035 | assign_all_jacks_automatically(struct umidi_softc *sc) | | 1035 | assign_all_jacks_automatically(struct umidi_softc *sc) |
1036 | { | | 1036 | { |
1037 | usbd_status err; | | 1037 | usbd_status err; |
1038 | int i; | | 1038 | int i; |
1039 | struct umidi_jack *out, *in; | | 1039 | struct umidi_jack *out, *in; |
1040 | const signed char *asg_spec; | | 1040 | const signed char *asg_spec; |
1041 | | | 1041 | |
1042 | err = | | 1042 | err = |
1043 | alloc_all_mididevs(sc, | | 1043 | alloc_all_mididevs(sc, |
1044 | max(sc->sc_out_num_jacks, sc->sc_in_num_jacks)); | | 1044 | max(sc->sc_out_num_jacks, sc->sc_in_num_jacks)); |
1045 | if (err!=USBD_NORMAL_COMPLETION) | | 1045 | if (err!=USBD_NORMAL_COMPLETION) |
1046 | return err; | | 1046 | return err; |
1047 | | | 1047 | |
1048 | if ( UMQ_ISTYPE(sc, UMQ_TYPE_MD_FIXED)) | | 1048 | if ( UMQ_ISTYPE(sc, UMQ_TYPE_MD_FIXED)) |
1049 | asg_spec = umidi_get_quirk_data_from_type(sc->sc_quirk, | | 1049 | asg_spec = umidi_get_quirk_data_from_type(sc->sc_quirk, |
1050 | UMQ_TYPE_MD_FIXED); | | 1050 | UMQ_TYPE_MD_FIXED); |
1051 | else | | 1051 | else |
1052 | asg_spec = NULL; | | 1052 | asg_spec = NULL; |
1053 | | | 1053 | |
1054 | for (i = 0; i < sc->sc_num_mididevs; i++) { | | 1054 | for (i = 0; i < sc->sc_num_mididevs; i++) { |
1055 | if (asg_spec != NULL) { | | 1055 | if (asg_spec != NULL) { |
1056 | if (*asg_spec == -1) | | 1056 | if (*asg_spec == -1) |
1057 | out = NULL; | | 1057 | out = NULL; |
1058 | else | | 1058 | else |
1059 | out = &sc->sc_out_jacks[*asg_spec]; | | 1059 | out = &sc->sc_out_jacks[*asg_spec]; |
1060 | ++ asg_spec; | | 1060 | ++ asg_spec; |
1061 | if (*asg_spec == -1) | | 1061 | if (*asg_spec == -1) |
1062 | in = NULL; | | 1062 | in = NULL; |
1063 | else | | 1063 | else |
1064 | in = &sc->sc_in_jacks[*asg_spec]; | | 1064 | in = &sc->sc_in_jacks[*asg_spec]; |
1065 | ++ asg_spec; | | 1065 | ++ asg_spec; |
1066 | } else { | | 1066 | } else { |
1067 | out = (i<sc->sc_out_num_jacks) ? &sc->sc_out_jacks[i] | | 1067 | out = (i<sc->sc_out_num_jacks) ? &sc->sc_out_jacks[i] |
1068 | : NULL; | | 1068 | : NULL; |
1069 | in = (i<sc->sc_in_num_jacks) ? &sc->sc_in_jacks[i] | | 1069 | in = (i<sc->sc_in_num_jacks) ? &sc->sc_in_jacks[i] |
1070 | : NULL; | | 1070 | : NULL; |
1071 | } | | 1071 | } |
1072 | err = bind_jacks_to_mididev(sc, out, in, &sc->sc_mididevs[i]); | | 1072 | err = bind_jacks_to_mididev(sc, out, in, &sc->sc_mididevs[i]); |
1073 | if (err!=USBD_NORMAL_COMPLETION) { | | 1073 | if (err!=USBD_NORMAL_COMPLETION) { |
1074 | free_all_mididevs(sc); | | 1074 | free_all_mididevs(sc); |
1075 | return err; | | 1075 | return err; |
1076 | } | | 1076 | } |
1077 | } | | 1077 | } |
1078 | | | 1078 | |
1079 | return USBD_NORMAL_COMPLETION; | | 1079 | return USBD_NORMAL_COMPLETION; |
1080 | } | | 1080 | } |
1081 | | | 1081 | |
1082 | static usbd_status | | 1082 | static usbd_status |
1083 | open_out_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *)) | | 1083 | open_out_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *)) |
1084 | { | | 1084 | { |
1085 | struct umidi_endpoint *ep = jack->endpoint; | | 1085 | struct umidi_endpoint *ep = jack->endpoint; |
1086 | struct umidi_softc *sc = ep->sc; | | 1086 | struct umidi_softc *sc = ep->sc; |
1087 | umidi_packet_bufp end; | | 1087 | umidi_packet_bufp end; |
1088 | int err; | | 1088 | int err; |
1089 | | | 1089 | |
1090 | KASSERT(mutex_owned(&sc->sc_lock)); | | 1090 | KASSERT(mutex_owned(&sc->sc_lock)); |
1091 | | | 1091 | |
1092 | if (jack->opened) | | 1092 | if (jack->opened) |
1093 | return USBD_IN_USE; | | 1093 | return USBD_IN_USE; |
1094 | | | 1094 | |
1095 | jack->arg = arg; | | 1095 | jack->arg = arg; |
1096 | jack->u.out.intr = intr; | | 1096 | jack->u.out.intr = intr; |
1097 | jack->midiman_ppkt = NULL; | | 1097 | jack->midiman_ppkt = NULL; |
1098 | end = ep->buffer + ep->buffer_size / sizeof *ep->buffer; | | 1098 | end = ep->buffer + ep->buffer_size / sizeof *ep->buffer; |
1099 | jack->opened = 1; | | 1099 | jack->opened = 1; |
1100 | ep->num_open++; | | 1100 | ep->num_open++; |
1101 | /* | | 1101 | /* |
1102 | * out_solicit maintains an invariant that there will always be | | 1102 | * out_solicit maintains an invariant that there will always be |
1103 | * (num_open - num_scheduled) slots free in the buffer. as we have | | 1103 | * (num_open - num_scheduled) slots free in the buffer. as we have |
1104 | * just incremented num_open, the buffer may be too full to satisfy | | 1104 | * just incremented num_open, the buffer may be too full to satisfy |
1105 | * the invariant until a transfer completes, for which we must wait. | | 1105 | * the invariant until a transfer completes, for which we must wait. |
1106 | */ | | 1106 | */ |
1107 | while (end - ep->next_slot < ep->num_open - ep->num_scheduled) { | | 1107 | while (end - ep->next_slot < ep->num_open - ep->num_scheduled) { |
1108 | err = cv_timedwait_sig(&sc->sc_cv, &sc->sc_lock, | | 1108 | err = cv_timedwait_sig(&sc->sc_cv, &sc->sc_lock, |
1109 | mstohz(10)); | | 1109 | mstohz(10)); |
1110 | if (err) { | | 1110 | if (err) { |
1111 | ep->num_open--; | | 1111 | ep->num_open--; |
1112 | jack->opened = 0; | | 1112 | jack->opened = 0; |
1113 | return USBD_IOERROR; | | 1113 | return USBD_IOERROR; |
1114 | } | | 1114 | } |
1115 | } | | 1115 | } |
1116 | | | 1116 | |
1117 | return USBD_NORMAL_COMPLETION; | | 1117 | return USBD_NORMAL_COMPLETION; |
1118 | } | | 1118 | } |
1119 | | | 1119 | |
1120 | static usbd_status | | 1120 | static usbd_status |
1121 | open_in_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *, int)) | | 1121 | open_in_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *, int)) |
1122 | { | | 1122 | { |
1123 | usbd_status err = USBD_NORMAL_COMPLETION; | | 1123 | usbd_status err = USBD_NORMAL_COMPLETION; |
1124 | struct umidi_endpoint *ep = jack->endpoint; | | 1124 | struct umidi_endpoint *ep = jack->endpoint; |
1125 | | | 1125 | |
1126 | KASSERT(mutex_owned(&ep->sc->sc_lock)); | | 1126 | KASSERT(mutex_owned(&ep->sc->sc_lock)); |
1127 | | | 1127 | |
1128 | if (jack->opened) | | 1128 | if (jack->opened) |
1129 | return USBD_IN_USE; | | 1129 | return USBD_IN_USE; |
1130 | | | 1130 | |
1131 | jack->arg = arg; | | 1131 | jack->arg = arg; |
1132 | jack->u.in.intr = intr; | | 1132 | jack->u.in.intr = intr; |
1133 | jack->opened = 1; | | 1133 | jack->opened = 1; |
1134 | if (ep->num_open++ == 0 && UE_GET_DIR(ep->addr)==UE_DIR_IN) { | | 1134 | if (ep->num_open++ == 0 && UE_GET_DIR(ep->addr)==UE_DIR_IN) { |
1135 | err = start_input_transfer(ep); | | 1135 | err = start_input_transfer(ep); |
1136 | if (err != USBD_NORMAL_COMPLETION && | | 1136 | if (err != USBD_NORMAL_COMPLETION && |
1137 | err != USBD_IN_PROGRESS) { | | 1137 | err != USBD_IN_PROGRESS) { |
1138 | ep->num_open--; | | 1138 | ep->num_open--; |
1139 | } | | 1139 | } |
1140 | } | | 1140 | } |
1141 | | | 1141 | |
1142 | return err; | | 1142 | return err; |
1143 | } | | 1143 | } |
1144 | | | 1144 | |
1145 | static void | | 1145 | static void |
1146 | close_out_jack(struct umidi_jack *jack) | | 1146 | close_out_jack(struct umidi_jack *jack) |
1147 | { | | 1147 | { |
1148 | struct umidi_endpoint *ep; | | 1148 | struct umidi_endpoint *ep; |
1149 | struct umidi_softc *sc; | | 1149 | struct umidi_softc *sc; |
1150 | u_int16_t mask; | | 1150 | u_int16_t mask; |
1151 | int err; | | 1151 | int err; |
1152 | | | 1152 | |
1153 | if (jack->opened) { | | 1153 | if (jack->opened) { |
1154 | ep = jack->endpoint; | | 1154 | ep = jack->endpoint; |
1155 | sc = ep->sc; | | 1155 | sc = ep->sc; |
1156 | mutex_spin_enter(&sc->sc_lock); | | 1156 | mutex_spin_enter(&sc->sc_lock); |
1157 | mask = 1 << (jack->cable_number); | | 1157 | mask = 1 << (jack->cable_number); |
1158 | while (mask & (ep->this_schedule | ep->next_schedule)) { | | 1158 | while (mask & (ep->this_schedule | ep->next_schedule)) { |
1159 | err = cv_timedwait_sig(&sc->sc_cv, &sc->sc_lock, | | 1159 | err = cv_timedwait_sig(&sc->sc_cv, &sc->sc_lock, |
1160 | mstohz(10)); | | 1160 | mstohz(10)); |
1161 | if (err) | | 1161 | if (err) |
1162 | break; | | 1162 | break; |
1163 | } | | 1163 | } |
1164 | /* | | 1164 | /* |
1165 | * We can re-enter this function from both close() and | | 1165 | * We can re-enter this function from both close() and |
1166 | * detach(). Make sure only one of them does this part. | | 1166 | * detach(). Make sure only one of them does this part. |
1167 | */ | | 1167 | */ |
1168 | if (jack->opened) { | | 1168 | if (jack->opened) { |
1169 | jack->opened = 0; | | 1169 | jack->opened = 0; |
1170 | jack->endpoint->num_open--; | | 1170 | jack->endpoint->num_open--; |
1171 | ep->this_schedule &= ~mask; | | 1171 | ep->this_schedule &= ~mask; |
1172 | ep->next_schedule &= ~mask; | | 1172 | ep->next_schedule &= ~mask; |
1173 | } | | 1173 | } |
1174 | mutex_spin_exit(&sc->sc_lock); | | 1174 | mutex_spin_exit(&sc->sc_lock); |
1175 | } | | 1175 | } |
1176 | } | | 1176 | } |
1177 | | | 1177 | |
1178 | static void | | 1178 | static void |
1179 | close_in_jack(struct umidi_jack *jack) | | 1179 | close_in_jack(struct umidi_jack *jack) |
1180 | { | | 1180 | { |
1181 | if (jack->opened) { | | 1181 | if (jack->opened) { |
1182 | jack->opened = 0; | | 1182 | jack->opened = 0; |
1183 | if (--jack->endpoint->num_open == 0) { | | 1183 | if (--jack->endpoint->num_open == 0) { |
1184 | usbd_abort_pipe(jack->endpoint->pipe); | | 1184 | usbd_abort_pipe(jack->endpoint->pipe); |
1185 | } | | 1185 | } |
1186 | } | | 1186 | } |
1187 | } | | 1187 | } |
1188 | | | 1188 | |
1189 | static usbd_status | | 1189 | static usbd_status |
1190 | attach_mididev(struct umidi_softc *sc, struct umidi_mididev *mididev) | | 1190 | attach_mididev(struct umidi_softc *sc, struct umidi_mididev *mididev) |
1191 | { | | 1191 | { |
1192 | if (mididev->sc) | | 1192 | if (mididev->sc) |
1193 | return USBD_IN_USE; | | 1193 | return USBD_IN_USE; |
1194 | | | 1194 | |
1195 | mididev->sc = sc; | | 1195 | mididev->sc = sc; |
1196 | | | 1196 | |
1197 | describe_mididev(mididev); | | 1197 | describe_mididev(mididev); |
1198 | | | 1198 | |
1199 | mididev->mdev = midi_attach_mi(&umidi_hw_if, mididev, sc->sc_dev); | | 1199 | mididev->mdev = midi_attach_mi(&umidi_hw_if, mididev, sc->sc_dev); |
1200 | | | 1200 | |
1201 | return USBD_NORMAL_COMPLETION; | | 1201 | return USBD_NORMAL_COMPLETION; |
1202 | } | | 1202 | } |
1203 | | | 1203 | |
1204 | static usbd_status | | 1204 | static usbd_status |
1205 | detach_mididev(struct umidi_mididev *mididev, int flags) | | 1205 | detach_mididev(struct umidi_mididev *mididev, int flags) |
1206 | { | | 1206 | { |
1207 | if (!mididev->sc) | | 1207 | if (!mididev->sc) |
1208 | return USBD_NO_ADDR; | | 1208 | return USBD_NO_ADDR; |
1209 | | | 1209 | |
1210 | if (mididev->opened) { | | 1210 | if (mididev->opened) { |
1211 | umidi_close(mididev); | | 1211 | umidi_close(mididev); |
1212 | } | | 1212 | } |
1213 | unbind_jacks_from_mididev(mididev); | | 1213 | unbind_jacks_from_mididev(mididev); |
1214 | | | 1214 | |
1215 | if (mididev->mdev != NULL) | | 1215 | if (mididev->mdev != NULL) |
1216 | config_detach(mididev->mdev, flags); | | 1216 | config_detach(mididev->mdev, flags); |
1217 | | | 1217 | |
1218 | if (NULL != mididev->label) { | | 1218 | if (NULL != mididev->label) { |
1219 | kmem_free(mididev->label, mididev->label_len); | | 1219 | kmem_free(mididev->label, mididev->label_len); |
1220 | mididev->label = NULL; | | 1220 | mididev->label = NULL; |
1221 | } | | 1221 | } |
1222 | | | 1222 | |
1223 | mididev->sc = NULL; | | 1223 | mididev->sc = NULL; |
1224 | | | 1224 | |
1225 | return USBD_NORMAL_COMPLETION; | | 1225 | return USBD_NORMAL_COMPLETION; |
1226 | } | | 1226 | } |
1227 | | | 1227 | |
1228 | static void | | 1228 | static void |
1229 | deactivate_mididev(struct umidi_mididev *mididev) | | 1229 | deactivate_mididev(struct umidi_mididev *mididev) |
1230 | { | | 1230 | { |
1231 | if (mididev->out_jack) | | 1231 | if (mididev->out_jack) |
1232 | mididev->out_jack->binded = 0; | | 1232 | mididev->out_jack->binded = 0; |
1233 | if (mididev->in_jack) | | 1233 | if (mididev->in_jack) |
1234 | mididev->in_jack->binded = 0; | | 1234 | mididev->in_jack->binded = 0; |
1235 | } | | 1235 | } |
1236 | | | 1236 | |
1237 | static usbd_status | | 1237 | static usbd_status |
1238 | alloc_all_mididevs(struct umidi_softc *sc, int nmidi) | | 1238 | alloc_all_mididevs(struct umidi_softc *sc, int nmidi) |
1239 | { | | 1239 | { |
1240 | sc->sc_num_mididevs = nmidi; | | 1240 | sc->sc_num_mididevs = nmidi; |
1241 | sc->sc_mididevs = kmem_zalloc(sizeof(*sc->sc_mididevs)*nmidi, KM_SLEEP); | | 1241 | sc->sc_mididevs = kmem_zalloc(sizeof(*sc->sc_mididevs)*nmidi, KM_SLEEP); |
1242 | if (!sc->sc_mididevs) | | 1242 | if (!sc->sc_mididevs) |
1243 | return USBD_NOMEM; | | 1243 | return USBD_NOMEM; |
1244 | | | 1244 | |
1245 | return USBD_NORMAL_COMPLETION; | | 1245 | return USBD_NORMAL_COMPLETION; |
1246 | } | | 1246 | } |
1247 | | | 1247 | |
1248 | static void | | 1248 | static void |
1249 | free_all_mididevs(struct umidi_softc *sc) | | 1249 | free_all_mididevs(struct umidi_softc *sc) |
1250 | { | | 1250 | { |
1251 | if (sc->sc_mididevs) | | 1251 | if (sc->sc_mididevs) |
1252 | kmem_free(sc->sc_mididevs, | | 1252 | kmem_free(sc->sc_mididevs, |
1253 | sizeof(*sc->sc_mididevs)*sc->sc_num_mididevs); | | 1253 | sizeof(*sc->sc_mididevs)*sc->sc_num_mididevs); |
1254 | sc->sc_num_mididevs = 0; | | 1254 | sc->sc_num_mididevs = 0; |
1255 | } | | 1255 | } |
1256 | | | 1256 | |
1257 | static usbd_status | | 1257 | static usbd_status |
1258 | attach_all_mididevs(struct umidi_softc *sc) | | 1258 | attach_all_mididevs(struct umidi_softc *sc) |
1259 | { | | 1259 | { |
1260 | usbd_status err; | | 1260 | usbd_status err; |
1261 | int i; | | 1261 | int i; |
1262 | | | 1262 | |
1263 | if (sc->sc_mididevs) | | 1263 | if (sc->sc_mididevs) |
1264 | for (i = 0; i < sc->sc_num_mididevs; i++) { | | 1264 | for (i = 0; i < sc->sc_num_mididevs; i++) { |
1265 | err = attach_mididev(sc, &sc->sc_mididevs[i]); | | 1265 | err = attach_mididev(sc, &sc->sc_mididevs[i]); |
1266 | if (err != USBD_NORMAL_COMPLETION) | | 1266 | if (err != USBD_NORMAL_COMPLETION) |
1267 | return err; | | 1267 | return err; |
1268 | } | | 1268 | } |
1269 | | | 1269 | |
1270 | return USBD_NORMAL_COMPLETION; | | 1270 | return USBD_NORMAL_COMPLETION; |
1271 | } | | 1271 | } |
1272 | | | 1272 | |
1273 | static usbd_status | | 1273 | static usbd_status |
1274 | detach_all_mididevs(struct umidi_softc *sc, int flags) | | 1274 | detach_all_mididevs(struct umidi_softc *sc, int flags) |
1275 | { | | 1275 | { |
1276 | usbd_status err; | | 1276 | usbd_status err; |
1277 | int i; | | 1277 | int i; |
1278 | | | 1278 | |
1279 | if (sc->sc_mididevs) | | 1279 | if (sc->sc_mididevs) |
1280 | for (i = 0; i < sc->sc_num_mididevs; i++) { | | 1280 | for (i = 0; i < sc->sc_num_mididevs; i++) { |
1281 | err = detach_mididev(&sc->sc_mididevs[i], flags); | | 1281 | err = detach_mididev(&sc->sc_mididevs[i], flags); |
1282 | if (err != USBD_NORMAL_COMPLETION) | | 1282 | if (err != USBD_NORMAL_COMPLETION) |
1283 | return err; | | 1283 | return err; |
1284 | } | | 1284 | } |
1285 | | | 1285 | |
1286 | return USBD_NORMAL_COMPLETION; | | 1286 | return USBD_NORMAL_COMPLETION; |
1287 | } | | 1287 | } |
1288 | | | 1288 | |
1289 | static void | | 1289 | static void |
1290 | deactivate_all_mididevs(struct umidi_softc *sc) | | 1290 | deactivate_all_mididevs(struct umidi_softc *sc) |
1291 | { | | 1291 | { |
1292 | int i; | | 1292 | int i; |
1293 | | | 1293 | |
1294 | if (sc->sc_mididevs) { | | 1294 | if (sc->sc_mididevs) { |
1295 | for (i = 0; i < sc->sc_num_mididevs; i++) | | 1295 | for (i = 0; i < sc->sc_num_mididevs; i++) |
1296 | deactivate_mididev(&sc->sc_mididevs[i]); | | 1296 | deactivate_mididev(&sc->sc_mididevs[i]); |
1297 | } | | 1297 | } |
1298 | } | | 1298 | } |
1299 | | | 1299 | |
1300 | /* | | 1300 | /* |
1301 | * TODO: the 0-based cable numbers will often not match the labeling of the | | 1301 | * TODO: the 0-based cable numbers will often not match the labeling of the |
1302 | * equipment. Ideally: | | 1302 | * equipment. Ideally: |
1303 | * For class-compliant devices: get the iJack string from the jack descriptor. | | 1303 | * For class-compliant devices: get the iJack string from the jack descriptor. |
1304 | * Otherwise: | | 1304 | * Otherwise: |
1305 | * - support a DISPLAY_BASE_CN quirk (add the value to each internal cable | | 1305 | * - support a DISPLAY_BASE_CN quirk (add the value to each internal cable |
1306 | * number for display) | | 1306 | * number for display) |
1307 | * - support an array quirk explictly giving a char * for each jack. | | 1307 | * - support an array quirk explictly giving a char * for each jack. |
1308 | * For now, you get 0-based cable numbers. If there are multiple endpoints and | | 1308 | * For now, you get 0-based cable numbers. If there are multiple endpoints and |
1309 | * the CNs are not globally unique, each is shown with its associated endpoint | | 1309 | * the CNs are not globally unique, each is shown with its associated endpoint |
1310 | * address in hex also. That should not be necessary when using iJack values | | 1310 | * address in hex also. That should not be necessary when using iJack values |
1311 | * or a quirk array. | | 1311 | * or a quirk array. |
1312 | */ | | 1312 | */ |
1313 | void | | 1313 | void |
1314 | describe_mididev(struct umidi_mididev *md) | | 1314 | describe_mididev(struct umidi_mididev *md) |
1315 | { | | 1315 | { |
1316 | char in_label[16]; | | 1316 | char in_label[16]; |
1317 | char out_label[16]; | | 1317 | char out_label[16]; |
1318 | const char *unit_label; | | 1318 | const char *unit_label; |
1319 | char *final_label; | | 1319 | char *final_label; |
1320 | struct umidi_softc *sc; | | 1320 | struct umidi_softc *sc; |
1321 | int show_ep_in; | | 1321 | int show_ep_in; |
1322 | int show_ep_out; | | 1322 | int show_ep_out; |
1323 | size_t len; | | 1323 | size_t len; |
1324 | | | 1324 | |
1325 | sc = md->sc; | | 1325 | sc = md->sc; |
1326 | show_ep_in = sc-> sc_in_num_endpoints > 1 && !sc->cblnums_global; | | 1326 | show_ep_in = sc-> sc_in_num_endpoints > 1 && !sc->cblnums_global; |
1327 | show_ep_out = sc->sc_out_num_endpoints > 1 && !sc->cblnums_global; | | 1327 | show_ep_out = sc->sc_out_num_endpoints > 1 && !sc->cblnums_global; |
1328 | | | 1328 | |
1329 | if ( NULL == md->in_jack ) | | 1329 | if ( NULL == md->in_jack ) |
1330 | in_label[0] = '\0'; | | 1330 | in_label[0] = '\0'; |
1331 | else if ( show_ep_in ) | | 1331 | else if ( show_ep_in ) |
1332 | snprintf(in_label, sizeof in_label, "<%d(%x) ", | | 1332 | snprintf(in_label, sizeof in_label, "<%d(%x) ", |
1333 | md->in_jack->cable_number, md->in_jack->endpoint->addr); | | 1333 | md->in_jack->cable_number, md->in_jack->endpoint->addr); |
1334 | else | | 1334 | else |
1335 | snprintf(in_label, sizeof in_label, "<%d ", | | 1335 | snprintf(in_label, sizeof in_label, "<%d ", |
1336 | md->in_jack->cable_number); | | 1336 | md->in_jack->cable_number); |
1337 | | | 1337 | |
1338 | if ( NULL == md->out_jack ) | | 1338 | if ( NULL == md->out_jack ) |
1339 | out_label[0] = '\0'; | | 1339 | out_label[0] = '\0'; |
1340 | else if ( show_ep_out ) | | 1340 | else if ( show_ep_out ) |
1341 | snprintf(out_label, sizeof out_label, ">%d(%x) ", | | 1341 | snprintf(out_label, sizeof out_label, ">%d(%x) ", |
1342 | md->out_jack->cable_number, md->out_jack->endpoint->addr); | | 1342 | md->out_jack->cable_number, md->out_jack->endpoint->addr); |
1343 | else | | 1343 | else |
1344 | snprintf(out_label, sizeof out_label, ">%d ", | | 1344 | snprintf(out_label, sizeof out_label, ">%d ", |
1345 | md->out_jack->cable_number); | | 1345 | md->out_jack->cable_number); |
1346 | | | 1346 | |
1347 | unit_label = device_xname(sc->sc_dev); | | 1347 | unit_label = device_xname(sc->sc_dev); |
1348 | | | 1348 | |
1349 | len = strlen(in_label) + strlen(out_label) + strlen(unit_label) + 4; | | 1349 | len = strlen(in_label) + strlen(out_label) + strlen(unit_label) + 4; |
1350 | | | 1350 | |
1351 | final_label = kmem_alloc(len, KM_SLEEP); | | 1351 | final_label = kmem_alloc(len, KM_SLEEP); |
1352 | | | 1352 | |
1353 | snprintf(final_label, len, "%s%son %s", | | 1353 | snprintf(final_label, len, "%s%son %s", |
1354 | in_label, out_label, unit_label); | | 1354 | in_label, out_label, unit_label); |
1355 | | | 1355 | |
1356 | md->label = final_label; | | 1356 | md->label = final_label; |
1357 | md->label_len = len; | | 1357 | md->label_len = len; |
1358 | } | | 1358 | } |
1359 | | | 1359 | |
1360 | #ifdef UMIDI_DEBUG | | 1360 | #ifdef UMIDI_DEBUG |
1361 | static void | | 1361 | static void |
1362 | dump_sc(struct umidi_softc *sc) | | 1362 | dump_sc(struct umidi_softc *sc) |
1363 | { | | 1363 | { |
1364 | int i; | | 1364 | int i; |
1365 | | | 1365 | |
1366 | DPRINTFN(10, ("%s: dump_sc\n", device_xname(sc->sc_dev))); | | 1366 | DPRINTFN(10, ("%s: dump_sc\n", device_xname(sc->sc_dev))); |
1367 | for (i=0; i<sc->sc_out_num_endpoints; i++) { | | 1367 | for (i=0; i<sc->sc_out_num_endpoints; i++) { |
1368 | DPRINTFN(10, ("\tout_ep(%p):\n", &sc->sc_out_ep[i])); | | 1368 | DPRINTFN(10, ("\tout_ep(%p):\n", &sc->sc_out_ep[i])); |
1369 | dump_ep(&sc->sc_out_ep[i]); | | 1369 | dump_ep(&sc->sc_out_ep[i]); |
1370 | } | | 1370 | } |
1371 | for (i=0; i<sc->sc_in_num_endpoints; i++) { | | 1371 | for (i=0; i<sc->sc_in_num_endpoints; i++) { |
1372 | DPRINTFN(10, ("\tin_ep(%p):\n", &sc->sc_in_ep[i])); | | 1372 | DPRINTFN(10, ("\tin_ep(%p):\n", &sc->sc_in_ep[i])); |
1373 | dump_ep(&sc->sc_in_ep[i]); | | 1373 | dump_ep(&sc->sc_in_ep[i]); |
1374 | } | | 1374 | } |
1375 | } | | 1375 | } |
1376 | | | 1376 | |
1377 | static void | | 1377 | static void |
1378 | dump_ep(struct umidi_endpoint *ep) | | 1378 | dump_ep(struct umidi_endpoint *ep) |
1379 | { | | 1379 | { |
1380 | int i; | | 1380 | int i; |
1381 | for (i=0; i<UMIDI_MAX_EPJACKS; i++) { | | 1381 | for (i=0; i<UMIDI_MAX_EPJACKS; i++) { |
1382 | if (NULL==ep->jacks[i]) | | 1382 | if (NULL==ep->jacks[i]) |
1383 | continue; | | 1383 | continue; |
1384 | DPRINTFN(10, ("\t\tjack[%d]:%p:\n", i, ep->jacks[i])); | | 1384 | DPRINTFN(10, ("\t\tjack[%d]:%p:\n", i, ep->jacks[i])); |
1385 | dump_jack(ep->jacks[i]); | | 1385 | dump_jack(ep->jacks[i]); |
1386 | } | | 1386 | } |
1387 | } | | 1387 | } |
1388 | static void | | 1388 | static void |
1389 | dump_jack(struct umidi_jack *jack) | | 1389 | dump_jack(struct umidi_jack *jack) |
1390 | { | | 1390 | { |
1391 | DPRINTFN(10, ("\t\t\tep=%p\n", | | 1391 | DPRINTFN(10, ("\t\t\tep=%p\n", |
1392 | jack->endpoint)); | | 1392 | jack->endpoint)); |
1393 | } | | 1393 | } |
1394 | | | 1394 | |
1395 | #endif /* UMIDI_DEBUG */ | | 1395 | #endif /* UMIDI_DEBUG */ |
1396 | | | 1396 | |
1397 | | | 1397 | |
1398 | | | 1398 | |
1399 | /* | | 1399 | /* |
1400 | * MUX MIDI PACKET | | 1400 | * MUX MIDI PACKET |
1401 | */ | | 1401 | */ |
1402 | | | 1402 | |
1403 | static const int packet_length[16] = { | | 1403 | static const int packet_length[16] = { |
1404 | /*0*/ -1, | | 1404 | /*0*/ -1, |
1405 | /*1*/ -1, | | 1405 | /*1*/ -1, |
1406 | /*2*/ 2, | | 1406 | /*2*/ 2, |
1407 | /*3*/ 3, | | 1407 | /*3*/ 3, |
1408 | /*4*/ 3, | | 1408 | /*4*/ 3, |
1409 | /*5*/ 1, | | 1409 | /*5*/ 1, |
1410 | /*6*/ 2, | | 1410 | /*6*/ 2, |
1411 | /*7*/ 3, | | 1411 | /*7*/ 3, |
1412 | /*8*/ 3, | | 1412 | /*8*/ 3, |
1413 | /*9*/ 3, | | 1413 | /*9*/ 3, |
1414 | /*A*/ 3, | | 1414 | /*A*/ 3, |
1415 | /*B*/ 3, | | 1415 | /*B*/ 3, |
1416 | /*C*/ 2, | | 1416 | /*C*/ 2, |
1417 | /*D*/ 2, | | 1417 | /*D*/ 2, |
1418 | /*E*/ 3, | | 1418 | /*E*/ 3, |
1419 | /*F*/ 1, | | 1419 | /*F*/ 1, |
1420 | }; | | 1420 | }; |
1421 | | | 1421 | |
1422 | #define GET_CN(p) (((unsigned char)(p)>>4)&0x0F) | | 1422 | #define GET_CN(p) (((unsigned char)(p)>>4)&0x0F) |
1423 | #define GET_CIN(p) ((unsigned char)(p)&0x0F) | | 1423 | #define GET_CIN(p) ((unsigned char)(p)&0x0F) |
1424 | #define MIX_CN_CIN(cn, cin) \ | | 1424 | #define MIX_CN_CIN(cn, cin) \ |
1425 | ((unsigned char)((((unsigned char)(cn)&0x0F)<<4)| \ | | 1425 | ((unsigned char)((((unsigned char)(cn)&0x0F)<<4)| \ |
1426 | ((unsigned char)(cin)&0x0F))) | | 1426 | ((unsigned char)(cin)&0x0F))) |
1427 | | | 1427 | |
1428 | static usbd_status | | 1428 | static usbd_status |
1429 | start_input_transfer(struct umidi_endpoint *ep) | | 1429 | start_input_transfer(struct umidi_endpoint *ep) |
1430 | { | | 1430 | { |
1431 | usbd_setup_xfer(ep->xfer, ep->pipe, | | 1431 | usbd_setup_xfer(ep->xfer, ep->pipe, |
1432 | (usbd_private_handle)ep, | | 1432 | (usbd_private_handle)ep, |
1433 | ep->buffer, ep->buffer_size, | | 1433 | ep->buffer, ep->buffer_size, |
1434 | USBD_SHORT_XFER_OK | USBD_NO_COPY, | | 1434 | USBD_SHORT_XFER_OK | USBD_NO_COPY, |
1435 | USBD_NO_TIMEOUT, in_intr); | | 1435 | USBD_NO_TIMEOUT, in_intr); |
1436 | return usbd_transfer(ep->xfer); | | 1436 | return usbd_transfer(ep->xfer); |
1437 | } | | 1437 | } |
1438 | | | 1438 | |
1439 | static usbd_status | | 1439 | static usbd_status |
1440 | start_output_transfer(struct umidi_endpoint *ep) | | 1440 | start_output_transfer(struct umidi_endpoint *ep) |
1441 | { | | 1441 | { |
1442 | usbd_status rv; | | 1442 | usbd_status rv; |
1443 | u_int32_t length; | | 1443 | u_int32_t length; |
1444 | int i; | | 1444 | int i; |
1445 | | | 1445 | |
1446 | length = (ep->next_slot - ep->buffer) * sizeof *ep->buffer; | | 1446 | length = (ep->next_slot - ep->buffer) * sizeof *ep->buffer; |
1447 | DPRINTFN(200,("umidi out transfer: start %p end %p length %u\n", | | 1447 | DPRINTFN(200,("umidi out transfer: start %p end %p length %u\n", |
1448 | ep->buffer, ep->next_slot, length)); | | 1448 | ep->buffer, ep->next_slot, length)); |
1449 | usbd_setup_xfer(ep->xfer, ep->pipe, | | 1449 | usbd_setup_xfer(ep->xfer, ep->pipe, |
1450 | (usbd_private_handle)ep, | | 1450 | (usbd_private_handle)ep, |
1451 | ep->buffer, length, | | 1451 | ep->buffer, length, |
1452 | USBD_NO_COPY, USBD_NO_TIMEOUT, out_intr); | | 1452 | USBD_NO_COPY, USBD_NO_TIMEOUT, out_intr); |
1453 | rv = usbd_transfer(ep->xfer); | | 1453 | rv = usbd_transfer(ep->xfer); |
1454 | | | 1454 | |
1455 | /* | | 1455 | /* |
1456 | * Once the transfer is scheduled, no more adding to partial | | 1456 | * Once the transfer is scheduled, no more adding to partial |
1457 | * packets within it. | | 1457 | * packets within it. |
1458 | */ | | 1458 | */ |
1459 | if (UMQ_ISTYPE(ep->sc, UMQ_TYPE_MIDIMAN_GARBLE)) { | | 1459 | if (UMQ_ISTYPE(ep->sc, UMQ_TYPE_MIDIMAN_GARBLE)) { |
1460 | for (i=0; i<UMIDI_MAX_EPJACKS; ++i) | | 1460 | for (i=0; i<UMIDI_MAX_EPJACKS; ++i) |
1461 | if (NULL != ep->jacks[i]) | | 1461 | if (NULL != ep->jacks[i]) |
1462 | ep->jacks[i]->midiman_ppkt = NULL; | | 1462 | ep->jacks[i]->midiman_ppkt = NULL; |
1463 | } | | 1463 | } |
1464 | | | 1464 | |
1465 | return rv; | | 1465 | return rv; |
1466 | } | | 1466 | } |
1467 | | | 1467 | |
1468 | #ifdef UMIDI_DEBUG | | 1468 | #ifdef UMIDI_DEBUG |
1469 | #define DPR_PACKET(dir, sc, p) \ | | 1469 | #define DPR_PACKET(dir, sc, p) \ |
1470 | if ((unsigned char)(p)[1]!=0xFE) \ | | 1470 | if ((unsigned char)(p)[1]!=0xFE) \ |
1471 | DPRINTFN(500, \ | | 1471 | DPRINTFN(500, \ |
1472 | ("%s: umidi packet(" #dir "): %02X %02X %02X %02X\n", \ | | 1472 | ("%s: umidi packet(" #dir "): %02X %02X %02X %02X\n", \ |
1473 | device_xname(sc->sc_dev), \ | | 1473 | device_xname(sc->sc_dev), \ |
1474 | (unsigned char)(p)[0], \ | | 1474 | (unsigned char)(p)[0], \ |
1475 | (unsigned char)(p)[1], \ | | 1475 | (unsigned char)(p)[1], \ |
1476 | (unsigned char)(p)[2], \ | | 1476 | (unsigned char)(p)[2], \ |
1477 | (unsigned char)(p)[3])); | | 1477 | (unsigned char)(p)[3])); |
1478 | #else | | 1478 | #else |
1479 | #define DPR_PACKET(dir, sc, p) | | 1479 | #define DPR_PACKET(dir, sc, p) |
1480 | #endif | | 1480 | #endif |
1481 | | | 1481 | |
1482 | /* | | 1482 | /* |
1483 | * A 4-byte Midiman packet superficially resembles a 4-byte USB MIDI packet | | 1483 | * A 4-byte Midiman packet superficially resembles a 4-byte USB MIDI packet |
1484 | * with the cable number and length in the last byte instead of the first, | | 1484 | * with the cable number and length in the last byte instead of the first, |
1485 | * but there the resemblance ends. Where a USB MIDI packet is a semantic | | 1485 | * but there the resemblance ends. Where a USB MIDI packet is a semantic |
1486 | * unit, a Midiman packet is just a wrapper for 1 to 3 bytes of raw MIDI | | 1486 | * unit, a Midiman packet is just a wrapper for 1 to 3 bytes of raw MIDI |
1487 | * with a cable nybble and a length nybble (which, unlike the CIN of a | | 1487 | * with a cable nybble and a length nybble (which, unlike the CIN of a |
1488 | * real USB MIDI packet, has no semantics at all besides the length). | | 1488 | * real USB MIDI packet, has no semantics at all besides the length). |
1489 | * A packet received from a Midiman may contain part of a MIDI message, | | 1489 | * A packet received from a Midiman may contain part of a MIDI message, |
1490 | * more than one MIDI message, or parts of more than one MIDI message. A | | 1490 | * more than one MIDI message, or parts of more than one MIDI message. A |
1491 | * three-byte MIDI message may arrive in three packets of data length 1, and | | 1491 | * three-byte MIDI message may arrive in three packets of data length 1, and |
1492 | * running status may be used. Happily, the midi(4) driver above us will put | | 1492 | * running status may be used. Happily, the midi(4) driver above us will put |
1493 | * it all back together, so the only cost is in USB bandwidth. The device | | 1493 | * it all back together, so the only cost is in USB bandwidth. The device |
1494 | * has an easier time with what it receives from us: we'll pack messages in | | 1494 | * has an easier time with what it receives from us: we'll pack messages in |
1495 | * and across packets, but filling the packets whenever possible and, | | 1495 | * and across packets, but filling the packets whenever possible and, |
1496 | * as midi(4) hands us a complete message at a time, we'll never send one | | 1496 | * as midi(4) hands us a complete message at a time, we'll never send one |
1497 | * in a dribble of short packets. | | 1497 | * in a dribble of short packets. |
1498 | */ | | 1498 | */ |
1499 | | | 1499 | |
1500 | static int | | 1500 | static int |
1501 | out_jack_output(struct umidi_jack *out_jack, u_char *src, int len, int cin) | | 1501 | out_jack_output(struct umidi_jack *out_jack, u_char *src, int len, int cin) |
1502 | { | | 1502 | { |
1503 | struct umidi_endpoint *ep = out_jack->endpoint; | | 1503 | struct umidi_endpoint *ep = out_jack->endpoint; |
1504 | struct umidi_softc *sc = ep->sc; | | 1504 | struct umidi_softc *sc = ep->sc; |
1505 | unsigned char *packet; | | 1505 | unsigned char *packet; |
1506 | int plen; | | 1506 | int plen; |
1507 | int poff; | | 1507 | int poff; |
1508 | | | 1508 | |
1509 | if (sc->sc_dying) | | 1509 | if (sc->sc_dying) |
1510 | return EIO; | | 1510 | return EIO; |
1511 | | | 1511 | |
1512 | if (!out_jack->opened) | | 1512 | if (!out_jack->opened) |
1513 | return ENODEV; /* XXX as it was, is this the right errno? */ | | 1513 | return ENODEV; /* XXX as it was, is this the right errno? */ |
1514 | | | 1514 | |
1515 | #ifdef UMIDI_DEBUG | | 1515 | #ifdef UMIDI_DEBUG |