1 /*
2  * Line6 Pod HD
3  *
4  * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
5  *
6  *	This program is free software; you can redistribute it and/or
7  *	modify it under the terms of the GNU General Public License as
8  *	published by the Free Software Foundation, version 2.
9  *
10  */
11 
12 #include <sound/core.h>
13 #include <sound/pcm.h>
14 
15 #include "audio.h"
16 #include "driver.h"
17 #include "pcm.h"
18 #include "podhd.h"
19 
20 #define PODHD_BYTES_PER_FRAME 6	/* 24bit audio (stereo) */
21 
22 static struct snd_ratden podhd_ratden = {
23 	.num_min = 48000,
24 	.num_max = 48000,
25 	.num_step = 1,
26 	.den = 1,
27 };
28 
29 static struct line6_pcm_properties podhd_pcm_properties = {
30 	.snd_line6_playback_hw = {
31 				  .info = (SNDRV_PCM_INFO_MMAP |
32 					   SNDRV_PCM_INFO_INTERLEAVED |
33 					   SNDRV_PCM_INFO_BLOCK_TRANSFER |
34 					   SNDRV_PCM_INFO_MMAP_VALID |
35 					   SNDRV_PCM_INFO_PAUSE |
36 #ifdef CONFIG_PM
37 					   SNDRV_PCM_INFO_RESUME |
38 #endif
39 					   SNDRV_PCM_INFO_SYNC_START),
40 				  .formats = SNDRV_PCM_FMTBIT_S24_3LE,
41 				  .rates = SNDRV_PCM_RATE_48000,
42 				  .rate_min = 48000,
43 				  .rate_max = 48000,
44 				  .channels_min = 2,
45 				  .channels_max = 2,
46 				  .buffer_bytes_max = 60000,
47 				  .period_bytes_min = 64,
48 				  .period_bytes_max = 8192,
49 				  .periods_min = 1,
50 				  .periods_max = 1024},
51 	.snd_line6_capture_hw = {
52 				 .info = (SNDRV_PCM_INFO_MMAP |
53 					  SNDRV_PCM_INFO_INTERLEAVED |
54 					  SNDRV_PCM_INFO_BLOCK_TRANSFER |
55 					  SNDRV_PCM_INFO_MMAP_VALID |
56 #ifdef CONFIG_PM
57 					  SNDRV_PCM_INFO_RESUME |
58 #endif
59 					  SNDRV_PCM_INFO_SYNC_START),
60 				 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
61 				 .rates = SNDRV_PCM_RATE_48000,
62 				 .rate_min = 48000,
63 				 .rate_max = 48000,
64 				 .channels_min = 2,
65 				 .channels_max = 2,
66 				 .buffer_bytes_max = 60000,
67 				 .period_bytes_min = 64,
68 				 .period_bytes_max = 8192,
69 				 .periods_min = 1,
70 				 .periods_max = 1024},
71 	.snd_line6_rates = {
72 			    .nrats = 1,
73 			    .rats = &podhd_ratden},
74 	.bytes_per_frame = PODHD_BYTES_PER_FRAME
75 };
76 
77 /*
78 	POD HD destructor.
79 */
podhd_destruct(struct usb_interface * interface)80 static void podhd_destruct(struct usb_interface *interface)
81 {
82 	struct usb_line6_podhd *podhd = usb_get_intfdata(interface);
83 
84 	if (podhd == NULL)
85 		return;
86 	line6_cleanup_audio(&podhd->line6);
87 }
88 
89 /*
90 	Try to init POD HD device.
91 */
podhd_try_init(struct usb_interface * interface,struct usb_line6_podhd * podhd)92 static int podhd_try_init(struct usb_interface *interface,
93 			  struct usb_line6_podhd *podhd)
94 {
95 	int err;
96 	struct usb_line6 *line6 = &podhd->line6;
97 
98 	if ((interface == NULL) || (podhd == NULL))
99 		return -ENODEV;
100 
101 	/* initialize audio system: */
102 	err = line6_init_audio(line6);
103 	if (err < 0)
104 		return err;
105 
106 	/* initialize MIDI subsystem: */
107 	err = line6_init_midi(line6);
108 	if (err < 0)
109 		return err;
110 
111 	/* initialize PCM subsystem: */
112 	err = line6_init_pcm(line6, &podhd_pcm_properties);
113 	if (err < 0)
114 		return err;
115 
116 	/* register USB audio system: */
117 	err = line6_register_audio(line6);
118 	return err;
119 }
120 
121 /*
122 	Init POD HD device (and clean up in case of failure).
123 */
line6_podhd_init(struct usb_interface * interface,struct usb_line6_podhd * podhd)124 int line6_podhd_init(struct usb_interface *interface,
125 		     struct usb_line6_podhd *podhd)
126 {
127 	int err = podhd_try_init(interface, podhd);
128 
129 	if (err < 0)
130 		podhd_destruct(interface);
131 
132 	return err;
133 }
134 
135 /*
136 	POD HD device disconnected.
137 */
line6_podhd_disconnect(struct usb_interface * interface)138 void line6_podhd_disconnect(struct usb_interface *interface)
139 {
140 	struct usb_line6_podhd *podhd;
141 
142 	if (interface == NULL)
143 		return;
144 	podhd = usb_get_intfdata(interface);
145 
146 	if (podhd != NULL) {
147 		struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm;
148 
149 		if (line6pcm != NULL)
150 			line6_pcm_disconnect(line6pcm);
151 	}
152 
153 	podhd_destruct(interface);
154 }
155