xref: /openbmc/linux/sound/usb/bcd2000/bcd2000.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b47a2229SMario Kicherer /*
3b47a2229SMario Kicherer  * Behringer BCD2000 driver
4b47a2229SMario Kicherer  *
5b47a2229SMario Kicherer  *   Copyright (C) 2014 Mario Kicherer (dev@kicherer.org)
6b47a2229SMario Kicherer  */
7b47a2229SMario Kicherer 
8b47a2229SMario Kicherer #include <linux/kernel.h>
9b47a2229SMario Kicherer #include <linux/errno.h>
10b47a2229SMario Kicherer #include <linux/init.h>
11b47a2229SMario Kicherer #include <linux/slab.h>
12b47a2229SMario Kicherer #include <linux/module.h>
13b47a2229SMario Kicherer #include <linux/bitmap.h>
14b47a2229SMario Kicherer #include <linux/usb.h>
15b47a2229SMario Kicherer #include <linux/usb/audio.h>
16b47a2229SMario Kicherer #include <sound/core.h>
17b47a2229SMario Kicherer #include <sound/initval.h>
18b47a2229SMario Kicherer #include <sound/rawmidi.h>
19b47a2229SMario Kicherer 
20b47a2229SMario Kicherer #define PREFIX "snd-bcd2000: "
21b47a2229SMario Kicherer #define BUFSIZE 64
22b47a2229SMario Kicherer 
235e055ea2SArvind Yadav static const struct usb_device_id id_table[] = {
24b47a2229SMario Kicherer 	{ USB_DEVICE(0x1397, 0x00bd) },
25b47a2229SMario Kicherer 	{ },
26b47a2229SMario Kicherer };
27b47a2229SMario Kicherer 
2871075c42STakashi Iwai static const unsigned char device_cmd_prefix[] = {0x03, 0x00};
29b47a2229SMario Kicherer 
3071075c42STakashi Iwai static const unsigned char bcd2000_init_sequence[] = {
31b47a2229SMario Kicherer 	0x07, 0x00, 0x00, 0x00, 0x78, 0x48, 0x1c, 0x81,
32b47a2229SMario Kicherer 	0xc4, 0x00, 0x00, 0x00, 0x5e, 0x53, 0x4a, 0xf7,
33b47a2229SMario Kicherer 	0x18, 0xfa, 0x11, 0xff, 0x6c, 0xf3, 0x90, 0xff,
34b47a2229SMario Kicherer 	0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
35b47a2229SMario Kicherer 	0x18, 0xfa, 0x11, 0xff, 0x14, 0x00, 0x00, 0x00,
36b47a2229SMario Kicherer 	0x00, 0x00, 0x00, 0x00, 0xf2, 0x34, 0x4a, 0xf7,
37b47a2229SMario Kicherer 	0x18, 0xfa, 0x11, 0xff
38b47a2229SMario Kicherer };
39b47a2229SMario Kicherer 
40b47a2229SMario Kicherer struct bcd2000 {
41b47a2229SMario Kicherer 	struct usb_device *dev;
42b47a2229SMario Kicherer 	struct snd_card *card;
43b47a2229SMario Kicherer 	struct usb_interface *intf;
44b47a2229SMario Kicherer 	int card_index;
45b47a2229SMario Kicherer 
46b47a2229SMario Kicherer 	int midi_out_active;
47b47a2229SMario Kicherer 	struct snd_rawmidi *rmidi;
48b47a2229SMario Kicherer 	struct snd_rawmidi_substream *midi_receive_substream;
49b47a2229SMario Kicherer 	struct snd_rawmidi_substream *midi_out_substream;
50b47a2229SMario Kicherer 
51b47a2229SMario Kicherer 	unsigned char midi_in_buf[BUFSIZE];
52b47a2229SMario Kicherer 	unsigned char midi_out_buf[BUFSIZE];
53b47a2229SMario Kicherer 
54b47a2229SMario Kicherer 	struct urb *midi_out_urb;
55b47a2229SMario Kicherer 	struct urb *midi_in_urb;
56b47a2229SMario Kicherer 
57b47a2229SMario Kicherer 	struct usb_anchor anchor;
58b47a2229SMario Kicherer };
59b47a2229SMario Kicherer 
60b47a2229SMario Kicherer static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
61b47a2229SMario Kicherer static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
62b47a2229SMario Kicherer 
63b47a2229SMario Kicherer static DEFINE_MUTEX(devices_mutex);
64574d69c2STakashi Iwai static DECLARE_BITMAP(devices_used, SNDRV_CARDS);
65b47a2229SMario Kicherer static struct usb_driver bcd2000_driver;
66b47a2229SMario Kicherer 
67b47a2229SMario Kicherer #ifdef CONFIG_SND_DEBUG
bcd2000_dump_buffer(const char * prefix,const char * buf,int len)68b47a2229SMario Kicherer static void bcd2000_dump_buffer(const char *prefix, const char *buf, int len)
69b47a2229SMario Kicherer {
70b47a2229SMario Kicherer 	print_hex_dump(KERN_DEBUG, prefix,
71b47a2229SMario Kicherer 			DUMP_PREFIX_NONE, 16, 1,
72b47a2229SMario Kicherer 			buf, len, false);
73b47a2229SMario Kicherer }
74b47a2229SMario Kicherer #else
bcd2000_dump_buffer(const char * prefix,const char * buf,int len)75b47a2229SMario Kicherer static void bcd2000_dump_buffer(const char *prefix, const char *buf, int len) {}
76b47a2229SMario Kicherer #endif
77b47a2229SMario Kicherer 
bcd2000_midi_input_open(struct snd_rawmidi_substream * substream)78b47a2229SMario Kicherer static int bcd2000_midi_input_open(struct snd_rawmidi_substream *substream)
79b47a2229SMario Kicherer {
80b47a2229SMario Kicherer 	return 0;
81b47a2229SMario Kicherer }
82b47a2229SMario Kicherer 
bcd2000_midi_input_close(struct snd_rawmidi_substream * substream)83b47a2229SMario Kicherer static int bcd2000_midi_input_close(struct snd_rawmidi_substream *substream)
84b47a2229SMario Kicherer {
85b47a2229SMario Kicherer 	return 0;
86b47a2229SMario Kicherer }
87b47a2229SMario Kicherer 
88b47a2229SMario Kicherer /* (de)register midi substream from client */
bcd2000_midi_input_trigger(struct snd_rawmidi_substream * substream,int up)89b47a2229SMario Kicherer static void bcd2000_midi_input_trigger(struct snd_rawmidi_substream *substream,
90b47a2229SMario Kicherer 						int up)
91b47a2229SMario Kicherer {
92b47a2229SMario Kicherer 	struct bcd2000 *bcd2k = substream->rmidi->private_data;
93b47a2229SMario Kicherer 	bcd2k->midi_receive_substream = up ? substream : NULL;
94b47a2229SMario Kicherer }
95b47a2229SMario Kicherer 
bcd2000_midi_handle_input(struct bcd2000 * bcd2k,const unsigned char * buf,unsigned int buf_len)96b47a2229SMario Kicherer static void bcd2000_midi_handle_input(struct bcd2000 *bcd2k,
97b47a2229SMario Kicherer 				const unsigned char *buf, unsigned int buf_len)
98b47a2229SMario Kicherer {
99b47a2229SMario Kicherer 	unsigned int payload_length, tocopy;
100b47a2229SMario Kicherer 	struct snd_rawmidi_substream *midi_receive_substream;
101b47a2229SMario Kicherer 
1026aa7de05SMark Rutland 	midi_receive_substream = READ_ONCE(bcd2k->midi_receive_substream);
103b47a2229SMario Kicherer 	if (!midi_receive_substream)
104b47a2229SMario Kicherer 		return;
105b47a2229SMario Kicherer 
106b47a2229SMario Kicherer 	bcd2000_dump_buffer(PREFIX "received from device: ", buf, buf_len);
107b47a2229SMario Kicherer 
108b47a2229SMario Kicherer 	if (buf_len < 2)
109b47a2229SMario Kicherer 		return;
110b47a2229SMario Kicherer 
111b47a2229SMario Kicherer 	payload_length = buf[0];
112b47a2229SMario Kicherer 
113b47a2229SMario Kicherer 	/* ignore packets without payload */
114b47a2229SMario Kicherer 	if (payload_length == 0)
115b47a2229SMario Kicherer 		return;
116b47a2229SMario Kicherer 
117b47a2229SMario Kicherer 	tocopy = min(payload_length, buf_len-1);
118b47a2229SMario Kicherer 
119b47a2229SMario Kicherer 	bcd2000_dump_buffer(PREFIX "sending to userspace: ",
120b47a2229SMario Kicherer 					&buf[1], tocopy);
121b47a2229SMario Kicherer 
122b47a2229SMario Kicherer 	snd_rawmidi_receive(midi_receive_substream,
123b47a2229SMario Kicherer 					&buf[1], tocopy);
124b47a2229SMario Kicherer }
125b47a2229SMario Kicherer 
bcd2000_midi_send(struct bcd2000 * bcd2k)126b47a2229SMario Kicherer static void bcd2000_midi_send(struct bcd2000 *bcd2k)
127b47a2229SMario Kicherer {
128b47a2229SMario Kicherer 	int len, ret;
129b47a2229SMario Kicherer 	struct snd_rawmidi_substream *midi_out_substream;
130b47a2229SMario Kicherer 
131b47a2229SMario Kicherer 	BUILD_BUG_ON(sizeof(device_cmd_prefix) >= BUFSIZE);
132b47a2229SMario Kicherer 
1336aa7de05SMark Rutland 	midi_out_substream = READ_ONCE(bcd2k->midi_out_substream);
134b47a2229SMario Kicherer 	if (!midi_out_substream)
135b47a2229SMario Kicherer 		return;
136b47a2229SMario Kicherer 
137b47a2229SMario Kicherer 	/* copy command prefix bytes */
138b47a2229SMario Kicherer 	memcpy(bcd2k->midi_out_buf, device_cmd_prefix,
139b47a2229SMario Kicherer 		sizeof(device_cmd_prefix));
140b47a2229SMario Kicherer 
141b47a2229SMario Kicherer 	/*
142b47a2229SMario Kicherer 	 * get MIDI packet and leave space for command prefix
143b47a2229SMario Kicherer 	 * and payload length
144b47a2229SMario Kicherer 	 */
145b47a2229SMario Kicherer 	len = snd_rawmidi_transmit(midi_out_substream,
146b47a2229SMario Kicherer 				bcd2k->midi_out_buf + 3, BUFSIZE - 3);
147b47a2229SMario Kicherer 
148b47a2229SMario Kicherer 	if (len < 0)
149b47a2229SMario Kicherer 		dev_err(&bcd2k->dev->dev, "%s: snd_rawmidi_transmit error %d\n",
150b47a2229SMario Kicherer 				__func__, len);
151b47a2229SMario Kicherer 
152b47a2229SMario Kicherer 	if (len <= 0)
153b47a2229SMario Kicherer 		return;
154b47a2229SMario Kicherer 
155b47a2229SMario Kicherer 	/* set payload length */
156b47a2229SMario Kicherer 	bcd2k->midi_out_buf[2] = len;
157b47a2229SMario Kicherer 	bcd2k->midi_out_urb->transfer_buffer_length = BUFSIZE;
158b47a2229SMario Kicherer 
159b47a2229SMario Kicherer 	bcd2000_dump_buffer(PREFIX "sending to device: ",
160b47a2229SMario Kicherer 			bcd2k->midi_out_buf, len+3);
161b47a2229SMario Kicherer 
162b47a2229SMario Kicherer 	/* send packet to the BCD2000 */
163b47a2229SMario Kicherer 	ret = usb_submit_urb(bcd2k->midi_out_urb, GFP_ATOMIC);
164b47a2229SMario Kicherer 	if (ret < 0)
165b47a2229SMario Kicherer 		dev_err(&bcd2k->dev->dev, PREFIX
166b47a2229SMario Kicherer 			"%s (%p): usb_submit_urb() failed, ret=%d, len=%d\n",
167b47a2229SMario Kicherer 			__func__, midi_out_substream, ret, len);
168b47a2229SMario Kicherer 	else
169b47a2229SMario Kicherer 		bcd2k->midi_out_active = 1;
170b47a2229SMario Kicherer }
171b47a2229SMario Kicherer 
bcd2000_midi_output_open(struct snd_rawmidi_substream * substream)172b47a2229SMario Kicherer static int bcd2000_midi_output_open(struct snd_rawmidi_substream *substream)
173b47a2229SMario Kicherer {
174b47a2229SMario Kicherer 	return 0;
175b47a2229SMario Kicherer }
176b47a2229SMario Kicherer 
bcd2000_midi_output_close(struct snd_rawmidi_substream * substream)177b47a2229SMario Kicherer static int bcd2000_midi_output_close(struct snd_rawmidi_substream *substream)
178b47a2229SMario Kicherer {
179b47a2229SMario Kicherer 	struct bcd2000 *bcd2k = substream->rmidi->private_data;
180b47a2229SMario Kicherer 
181b47a2229SMario Kicherer 	if (bcd2k->midi_out_active) {
182b47a2229SMario Kicherer 		usb_kill_urb(bcd2k->midi_out_urb);
183b47a2229SMario Kicherer 		bcd2k->midi_out_active = 0;
184b47a2229SMario Kicherer 	}
185b47a2229SMario Kicherer 
186b47a2229SMario Kicherer 	return 0;
187b47a2229SMario Kicherer }
188b47a2229SMario Kicherer 
189b47a2229SMario Kicherer /* (de)register midi substream from client */
bcd2000_midi_output_trigger(struct snd_rawmidi_substream * substream,int up)190b47a2229SMario Kicherer static void bcd2000_midi_output_trigger(struct snd_rawmidi_substream *substream,
191b47a2229SMario Kicherer 						int up)
192b47a2229SMario Kicherer {
193b47a2229SMario Kicherer 	struct bcd2000 *bcd2k = substream->rmidi->private_data;
194b47a2229SMario Kicherer 
195b47a2229SMario Kicherer 	if (up) {
196b47a2229SMario Kicherer 		bcd2k->midi_out_substream = substream;
197b47a2229SMario Kicherer 		/* check if there is data userspace wants to send */
198b47a2229SMario Kicherer 		if (!bcd2k->midi_out_active)
199b47a2229SMario Kicherer 			bcd2000_midi_send(bcd2k);
200b47a2229SMario Kicherer 	} else {
201b47a2229SMario Kicherer 		bcd2k->midi_out_substream = NULL;
202b47a2229SMario Kicherer 	}
203b47a2229SMario Kicherer }
204b47a2229SMario Kicherer 
bcd2000_output_complete(struct urb * urb)205b47a2229SMario Kicherer static void bcd2000_output_complete(struct urb *urb)
206b47a2229SMario Kicherer {
207b47a2229SMario Kicherer 	struct bcd2000 *bcd2k = urb->context;
208b47a2229SMario Kicherer 
209b47a2229SMario Kicherer 	bcd2k->midi_out_active = 0;
210b47a2229SMario Kicherer 
211b47a2229SMario Kicherer 	if (urb->status)
212b47a2229SMario Kicherer 		dev_warn(&urb->dev->dev,
213b47a2229SMario Kicherer 			PREFIX "output urb->status: %d\n", urb->status);
214b47a2229SMario Kicherer 
215b47a2229SMario Kicherer 	if (urb->status == -ESHUTDOWN)
216b47a2229SMario Kicherer 		return;
217b47a2229SMario Kicherer 
218b47a2229SMario Kicherer 	/* check if there is more data userspace wants to send */
219b47a2229SMario Kicherer 	bcd2000_midi_send(bcd2k);
220b47a2229SMario Kicherer }
221b47a2229SMario Kicherer 
bcd2000_input_complete(struct urb * urb)222b47a2229SMario Kicherer static void bcd2000_input_complete(struct urb *urb)
223b47a2229SMario Kicherer {
224b47a2229SMario Kicherer 	int ret;
225b47a2229SMario Kicherer 	struct bcd2000 *bcd2k = urb->context;
226b47a2229SMario Kicherer 
227b47a2229SMario Kicherer 	if (urb->status)
228b47a2229SMario Kicherer 		dev_warn(&urb->dev->dev,
229b47a2229SMario Kicherer 			PREFIX "input urb->status: %i\n", urb->status);
230b47a2229SMario Kicherer 
231b47a2229SMario Kicherer 	if (!bcd2k || urb->status == -ESHUTDOWN)
232b47a2229SMario Kicherer 		return;
233b47a2229SMario Kicherer 
234b47a2229SMario Kicherer 	if (urb->actual_length > 0)
235b47a2229SMario Kicherer 		bcd2000_midi_handle_input(bcd2k, urb->transfer_buffer,
236b47a2229SMario Kicherer 					urb->actual_length);
237b47a2229SMario Kicherer 
238b47a2229SMario Kicherer 	/* return URB to device */
239b47a2229SMario Kicherer 	ret = usb_submit_urb(bcd2k->midi_in_urb, GFP_ATOMIC);
240b47a2229SMario Kicherer 	if (ret < 0)
241b47a2229SMario Kicherer 		dev_err(&bcd2k->dev->dev, PREFIX
242b47a2229SMario Kicherer 			"%s: usb_submit_urb() failed, ret=%d\n",
243b47a2229SMario Kicherer 			__func__, ret);
244b47a2229SMario Kicherer }
245b47a2229SMario Kicherer 
246f43e5407STakashi Iwai static const struct snd_rawmidi_ops bcd2000_midi_output = {
247b47a2229SMario Kicherer 	.open =    bcd2000_midi_output_open,
248b47a2229SMario Kicherer 	.close =   bcd2000_midi_output_close,
249b47a2229SMario Kicherer 	.trigger = bcd2000_midi_output_trigger,
250b47a2229SMario Kicherer };
251b47a2229SMario Kicherer 
252f43e5407STakashi Iwai static const struct snd_rawmidi_ops bcd2000_midi_input = {
253b47a2229SMario Kicherer 	.open =    bcd2000_midi_input_open,
254b47a2229SMario Kicherer 	.close =   bcd2000_midi_input_close,
255b47a2229SMario Kicherer 	.trigger = bcd2000_midi_input_trigger,
256b47a2229SMario Kicherer };
257b47a2229SMario Kicherer 
bcd2000_init_device(struct bcd2000 * bcd2k)258b47a2229SMario Kicherer static void bcd2000_init_device(struct bcd2000 *bcd2k)
259b47a2229SMario Kicherer {
260b47a2229SMario Kicherer 	int ret;
261b47a2229SMario Kicherer 
262b47a2229SMario Kicherer 	init_usb_anchor(&bcd2k->anchor);
263b47a2229SMario Kicherer 	usb_anchor_urb(bcd2k->midi_out_urb, &bcd2k->anchor);
264b47a2229SMario Kicherer 	usb_anchor_urb(bcd2k->midi_in_urb, &bcd2k->anchor);
265b47a2229SMario Kicherer 
266b47a2229SMario Kicherer 	/* copy init sequence into buffer */
267b47a2229SMario Kicherer 	memcpy(bcd2k->midi_out_buf, bcd2000_init_sequence, 52);
268b47a2229SMario Kicherer 	bcd2k->midi_out_urb->transfer_buffer_length = 52;
269b47a2229SMario Kicherer 
270b47a2229SMario Kicherer 	/* submit sequence */
271b47a2229SMario Kicherer 	ret = usb_submit_urb(bcd2k->midi_out_urb, GFP_KERNEL);
272b47a2229SMario Kicherer 	if (ret < 0)
273b47a2229SMario Kicherer 		dev_err(&bcd2k->dev->dev, PREFIX
274b47a2229SMario Kicherer 			"%s: usb_submit_urb() out failed, ret=%d: ",
275b47a2229SMario Kicherer 			__func__, ret);
276b47a2229SMario Kicherer 	else
277b47a2229SMario Kicherer 		bcd2k->midi_out_active = 1;
278b47a2229SMario Kicherer 
279b47a2229SMario Kicherer 	/* pass URB to device to enable button and controller events */
280b47a2229SMario Kicherer 	ret = usb_submit_urb(bcd2k->midi_in_urb, GFP_KERNEL);
281b47a2229SMario Kicherer 	if (ret < 0)
282b47a2229SMario Kicherer 		dev_err(&bcd2k->dev->dev, PREFIX
283b47a2229SMario Kicherer 			"%s: usb_submit_urb() in failed, ret=%d: ",
284b47a2229SMario Kicherer 			__func__, ret);
285b47a2229SMario Kicherer 
286b47a2229SMario Kicherer 	/* ensure initialization is finished */
287b47a2229SMario Kicherer 	usb_wait_anchor_empty_timeout(&bcd2k->anchor, 1000);
288b47a2229SMario Kicherer }
289b47a2229SMario Kicherer 
bcd2000_init_midi(struct bcd2000 * bcd2k)290b47a2229SMario Kicherer static int bcd2000_init_midi(struct bcd2000 *bcd2k)
291b47a2229SMario Kicherer {
292b47a2229SMario Kicherer 	int ret;
293b47a2229SMario Kicherer 	struct snd_rawmidi *rmidi;
294b47a2229SMario Kicherer 
295b47a2229SMario Kicherer 	ret = snd_rawmidi_new(bcd2k->card, bcd2k->card->shortname, 0,
296b47a2229SMario Kicherer 					1, /* output */
297b47a2229SMario Kicherer 					1, /* input */
298b47a2229SMario Kicherer 					&rmidi);
299b47a2229SMario Kicherer 
300b47a2229SMario Kicherer 	if (ret < 0)
301b47a2229SMario Kicherer 		return ret;
302b47a2229SMario Kicherer 
30375b1a8f9SJoe Perches 	strscpy(rmidi->name, bcd2k->card->shortname, sizeof(rmidi->name));
304b47a2229SMario Kicherer 
305b47a2229SMario Kicherer 	rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX;
306b47a2229SMario Kicherer 	rmidi->private_data = bcd2k;
307b47a2229SMario Kicherer 
308b47a2229SMario Kicherer 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
309b47a2229SMario Kicherer 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
310b47a2229SMario Kicherer 					&bcd2000_midi_output);
311b47a2229SMario Kicherer 
312b47a2229SMario Kicherer 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
313b47a2229SMario Kicherer 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
314b47a2229SMario Kicherer 					&bcd2000_midi_input);
315b47a2229SMario Kicherer 
316b47a2229SMario Kicherer 	bcd2k->rmidi = rmidi;
317b47a2229SMario Kicherer 
318b47a2229SMario Kicherer 	bcd2k->midi_in_urb = usb_alloc_urb(0, GFP_KERNEL);
319b47a2229SMario Kicherer 	bcd2k->midi_out_urb = usb_alloc_urb(0, GFP_KERNEL);
320b47a2229SMario Kicherer 
321b47a2229SMario Kicherer 	if (!bcd2k->midi_in_urb || !bcd2k->midi_out_urb) {
322b47a2229SMario Kicherer 		dev_err(&bcd2k->dev->dev, PREFIX "usb_alloc_urb failed\n");
323b47a2229SMario Kicherer 		return -ENOMEM;
324b47a2229SMario Kicherer 	}
325b47a2229SMario Kicherer 
326b47a2229SMario Kicherer 	usb_fill_int_urb(bcd2k->midi_in_urb, bcd2k->dev,
327b47a2229SMario Kicherer 				usb_rcvintpipe(bcd2k->dev, 0x81),
328b47a2229SMario Kicherer 				bcd2k->midi_in_buf, BUFSIZE,
329b47a2229SMario Kicherer 				bcd2000_input_complete, bcd2k, 1);
330b47a2229SMario Kicherer 
331b47a2229SMario Kicherer 	usb_fill_int_urb(bcd2k->midi_out_urb, bcd2k->dev,
332b47a2229SMario Kicherer 				usb_sndintpipe(bcd2k->dev, 0x1),
333b47a2229SMario Kicherer 				bcd2k->midi_out_buf, BUFSIZE,
334b47a2229SMario Kicherer 				bcd2000_output_complete, bcd2k, 1);
335b47a2229SMario Kicherer 
3366815a0b4STakashi Iwai 	/* sanity checks of EPs before actually submitting */
3376815a0b4STakashi Iwai 	if (usb_urb_ep_type_check(bcd2k->midi_in_urb) ||
3386815a0b4STakashi Iwai 	    usb_urb_ep_type_check(bcd2k->midi_out_urb)) {
3396815a0b4STakashi Iwai 		dev_err(&bcd2k->dev->dev, "invalid MIDI EP\n");
3406815a0b4STakashi Iwai 		return -EINVAL;
3416815a0b4STakashi Iwai 	}
3426815a0b4STakashi Iwai 
343b47a2229SMario Kicherer 	bcd2000_init_device(bcd2k);
344b47a2229SMario Kicherer 
345b47a2229SMario Kicherer 	return 0;
346b47a2229SMario Kicherer }
347b47a2229SMario Kicherer 
bcd2000_free_usb_related_resources(struct bcd2000 * bcd2k,struct usb_interface * interface)348b47a2229SMario Kicherer static void bcd2000_free_usb_related_resources(struct bcd2000 *bcd2k,
349b47a2229SMario Kicherer 						struct usb_interface *interface)
350b47a2229SMario Kicherer {
351ffb2759dSZheyu Ma 	usb_kill_urb(bcd2k->midi_out_urb);
352ffb2759dSZheyu Ma 	usb_kill_urb(bcd2k->midi_in_urb);
353b47a2229SMario Kicherer 
354b47a2229SMario Kicherer 	usb_free_urb(bcd2k->midi_out_urb);
355b47a2229SMario Kicherer 	usb_free_urb(bcd2k->midi_in_urb);
356b47a2229SMario Kicherer 
357b47a2229SMario Kicherer 	if (bcd2k->intf) {
358b47a2229SMario Kicherer 		usb_set_intfdata(bcd2k->intf, NULL);
359b47a2229SMario Kicherer 		bcd2k->intf = NULL;
360b47a2229SMario Kicherer 	}
361b47a2229SMario Kicherer }
362b47a2229SMario Kicherer 
bcd2000_probe(struct usb_interface * interface,const struct usb_device_id * usb_id)363b47a2229SMario Kicherer static int bcd2000_probe(struct usb_interface *interface,
364b47a2229SMario Kicherer 				const struct usb_device_id *usb_id)
365b47a2229SMario Kicherer {
366b47a2229SMario Kicherer 	struct snd_card *card;
367b47a2229SMario Kicherer 	struct bcd2000 *bcd2k;
368b47a2229SMario Kicherer 	unsigned int card_index;
369b47a2229SMario Kicherer 	char usb_path[32];
370b47a2229SMario Kicherer 	int err;
371b47a2229SMario Kicherer 
372b47a2229SMario Kicherer 	mutex_lock(&devices_mutex);
373b47a2229SMario Kicherer 
374b47a2229SMario Kicherer 	for (card_index = 0; card_index < SNDRV_CARDS; ++card_index)
375b47a2229SMario Kicherer 		if (!test_bit(card_index, devices_used))
376b47a2229SMario Kicherer 			break;
377b47a2229SMario Kicherer 
378b47a2229SMario Kicherer 	if (card_index >= SNDRV_CARDS) {
379b47a2229SMario Kicherer 		mutex_unlock(&devices_mutex);
380b47a2229SMario Kicherer 		return -ENOENT;
381b47a2229SMario Kicherer 	}
382b47a2229SMario Kicherer 
383b47a2229SMario Kicherer 	err = snd_card_new(&interface->dev, index[card_index], id[card_index],
384b47a2229SMario Kicherer 			THIS_MODULE, sizeof(*bcd2k), &card);
385b47a2229SMario Kicherer 	if (err < 0) {
386b47a2229SMario Kicherer 		mutex_unlock(&devices_mutex);
387b47a2229SMario Kicherer 		return err;
388b47a2229SMario Kicherer 	}
389b47a2229SMario Kicherer 
390b47a2229SMario Kicherer 	bcd2k = card->private_data;
391b47a2229SMario Kicherer 	bcd2k->dev = interface_to_usbdev(interface);
392b47a2229SMario Kicherer 	bcd2k->card = card;
393b47a2229SMario Kicherer 	bcd2k->card_index = card_index;
394b47a2229SMario Kicherer 	bcd2k->intf = interface;
395b47a2229SMario Kicherer 
396b47a2229SMario Kicherer 	snd_card_set_dev(card, &interface->dev);
397b47a2229SMario Kicherer 
398*2ad27caaSJustin Stitt 	strscpy(card->driver, "snd-bcd2000", sizeof(card->driver));
399*2ad27caaSJustin Stitt 	strscpy(card->shortname, "BCD2000", sizeof(card->shortname));
400b47a2229SMario Kicherer 	usb_make_path(bcd2k->dev, usb_path, sizeof(usb_path));
401b47a2229SMario Kicherer 	snprintf(bcd2k->card->longname, sizeof(bcd2k->card->longname),
402b47a2229SMario Kicherer 		    "Behringer BCD2000 at %s",
403b47a2229SMario Kicherer 			usb_path);
404b47a2229SMario Kicherer 
405b47a2229SMario Kicherer 	err = bcd2000_init_midi(bcd2k);
406b47a2229SMario Kicherer 	if (err < 0)
407b47a2229SMario Kicherer 		goto probe_error;
408b47a2229SMario Kicherer 
409b47a2229SMario Kicherer 	err = snd_card_register(card);
410b47a2229SMario Kicherer 	if (err < 0)
411b47a2229SMario Kicherer 		goto probe_error;
412b47a2229SMario Kicherer 
413b47a2229SMario Kicherer 	usb_set_intfdata(interface, bcd2k);
414b47a2229SMario Kicherer 	set_bit(card_index, devices_used);
415b47a2229SMario Kicherer 
416b47a2229SMario Kicherer 	mutex_unlock(&devices_mutex);
417b47a2229SMario Kicherer 	return 0;
418b47a2229SMario Kicherer 
419b47a2229SMario Kicherer probe_error:
420b47a2229SMario Kicherer 	dev_info(&bcd2k->dev->dev, PREFIX "error during probing");
421b47a2229SMario Kicherer 	bcd2000_free_usb_related_resources(bcd2k, interface);
422b47a2229SMario Kicherer 	snd_card_free(card);
423b47a2229SMario Kicherer 	mutex_unlock(&devices_mutex);
424b47a2229SMario Kicherer 	return err;
425b47a2229SMario Kicherer }
426b47a2229SMario Kicherer 
bcd2000_disconnect(struct usb_interface * interface)427b47a2229SMario Kicherer static void bcd2000_disconnect(struct usb_interface *interface)
428b47a2229SMario Kicherer {
429b47a2229SMario Kicherer 	struct bcd2000 *bcd2k = usb_get_intfdata(interface);
430b47a2229SMario Kicherer 
431b47a2229SMario Kicherer 	if (!bcd2k)
432b47a2229SMario Kicherer 		return;
433b47a2229SMario Kicherer 
434b47a2229SMario Kicherer 	mutex_lock(&devices_mutex);
435b47a2229SMario Kicherer 
436b47a2229SMario Kicherer 	/* make sure that userspace cannot create new requests */
437b47a2229SMario Kicherer 	snd_card_disconnect(bcd2k->card);
438b47a2229SMario Kicherer 
439b47a2229SMario Kicherer 	bcd2000_free_usb_related_resources(bcd2k, interface);
440b47a2229SMario Kicherer 
441b47a2229SMario Kicherer 	clear_bit(bcd2k->card_index, devices_used);
442b47a2229SMario Kicherer 
443b47a2229SMario Kicherer 	snd_card_free_when_closed(bcd2k->card);
444b47a2229SMario Kicherer 
445b47a2229SMario Kicherer 	mutex_unlock(&devices_mutex);
446b47a2229SMario Kicherer }
447b47a2229SMario Kicherer 
448b47a2229SMario Kicherer static struct usb_driver bcd2000_driver = {
449b47a2229SMario Kicherer 	.name =		"snd-bcd2000",
450b47a2229SMario Kicherer 	.probe =	bcd2000_probe,
451b47a2229SMario Kicherer 	.disconnect =	bcd2000_disconnect,
452b47a2229SMario Kicherer 	.id_table =	id_table,
453b47a2229SMario Kicherer };
454b47a2229SMario Kicherer 
455b47a2229SMario Kicherer module_usb_driver(bcd2000_driver);
456b47a2229SMario Kicherer 
457b47a2229SMario Kicherer MODULE_DEVICE_TABLE(usb, id_table);
458b47a2229SMario Kicherer MODULE_AUTHOR("Mario Kicherer, dev@kicherer.org");
459b47a2229SMario Kicherer MODULE_DESCRIPTION("Behringer BCD2000 driver");
460b47a2229SMario Kicherer MODULE_LICENSE("GPL");
461