diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-05-22 04:01:29 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-05-22 04:01:29 -0400 |
commit | 02e5fbf622aabf68bdc02282a17a3aeed054237a (patch) | |
tree | 60f2d4e09464dbf338c832bb39f861f29779b86b /sound/usb/6fire | |
parent | b759b3ac9aee3afb01c21b603970ebb200c8048e (diff) | |
parent | bfe9fc8aebc997ce8bcf8ac0586c84a247812064 (diff) |
Merge branch 'topic/misc' into for-linus
Diffstat (limited to 'sound/usb/6fire')
-rw-r--r-- | sound/usb/6fire/control.c | 105 | ||||
-rw-r--r-- | sound/usb/6fire/control.h | 17 | ||||
-rw-r--r-- | sound/usb/6fire/firmware.c | 73 | ||||
-rw-r--r-- | sound/usb/6fire/pcm.c | 97 |
4 files changed, 193 insertions, 99 deletions
diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c index 248463511186..ac828eff1a63 100644 --- a/sound/usb/6fire/control.c +++ b/sound/usb/6fire/control.c | |||
@@ -65,6 +65,15 @@ init_data[] = { | |||
65 | { 0 } /* TERMINATING ENTRY */ | 65 | { 0 } /* TERMINATING ENTRY */ |
66 | }; | 66 | }; |
67 | 67 | ||
68 | static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 }; | ||
69 | /* values to write to soundcard register for all samplerates */ | ||
70 | static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; | ||
71 | static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; | ||
72 | |||
73 | enum { | ||
74 | DIGITAL_THRU_ONLY_SAMPLERATE = 3 | ||
75 | }; | ||
76 | |||
68 | static void usb6fire_control_master_vol_update(struct control_runtime *rt) | 77 | static void usb6fire_control_master_vol_update(struct control_runtime *rt) |
69 | { | 78 | { |
70 | struct comm_runtime *comm_rt = rt->chip->comm; | 79 | struct comm_runtime *comm_rt = rt->chip->comm; |
@@ -95,6 +104,67 @@ static void usb6fire_control_opt_coax_update(struct control_runtime *rt) | |||
95 | } | 104 | } |
96 | } | 105 | } |
97 | 106 | ||
107 | static int usb6fire_control_set_rate(struct control_runtime *rt, int rate) | ||
108 | { | ||
109 | int ret; | ||
110 | struct usb_device *device = rt->chip->dev; | ||
111 | struct comm_runtime *comm_rt = rt->chip->comm; | ||
112 | |||
113 | if (rate < 0 || rate >= CONTROL_N_RATES) | ||
114 | return -EINVAL; | ||
115 | |||
116 | ret = usb_set_interface(device, 1, rates_altsetting[rate]); | ||
117 | if (ret < 0) | ||
118 | return ret; | ||
119 | |||
120 | /* set soundcard clock */ | ||
121 | ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate], | ||
122 | rates_6fire_vh[rate]); | ||
123 | if (ret < 0) | ||
124 | return ret; | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static int usb6fire_control_set_channels( | ||
130 | struct control_runtime *rt, int n_analog_out, | ||
131 | int n_analog_in, bool spdif_out, bool spdif_in) | ||
132 | { | ||
133 | int ret; | ||
134 | struct comm_runtime *comm_rt = rt->chip->comm; | ||
135 | |||
136 | /* enable analog inputs and outputs | ||
137 | * (one bit per stereo-channel) */ | ||
138 | ret = comm_rt->write16(comm_rt, 0x02, 0x02, | ||
139 | (1 << (n_analog_out / 2)) - 1, | ||
140 | (1 << (n_analog_in / 2)) - 1); | ||
141 | if (ret < 0) | ||
142 | return ret; | ||
143 | |||
144 | /* disable digital inputs and outputs */ | ||
145 | /* TODO: use spdif_x to enable/disable digital channels */ | ||
146 | ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00); | ||
147 | if (ret < 0) | ||
148 | return ret; | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int usb6fire_control_streaming_update(struct control_runtime *rt) | ||
154 | { | ||
155 | struct comm_runtime *comm_rt = rt->chip->comm; | ||
156 | |||
157 | if (comm_rt) { | ||
158 | if (!rt->usb_streaming && rt->digital_thru_switch) | ||
159 | usb6fire_control_set_rate(rt, | ||
160 | DIGITAL_THRU_ONLY_SAMPLERATE); | ||
161 | return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, | ||
162 | (rt->usb_streaming ? 0x01 : 0x00) | | ||
163 | (rt->digital_thru_switch ? 0x08 : 0x00)); | ||
164 | } | ||
165 | return -EINVAL; | ||
166 | } | ||
167 | |||
98 | static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol, | 168 | static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol, |
99 | struct snd_ctl_elem_info *uinfo) | 169 | struct snd_ctl_elem_info *uinfo) |
100 | { | 170 | { |
@@ -195,6 +265,28 @@ static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol, | |||
195 | return 0; | 265 | return 0; |
196 | } | 266 | } |
197 | 267 | ||
268 | static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol, | ||
269 | struct snd_ctl_elem_value *ucontrol) | ||
270 | { | ||
271 | struct control_runtime *rt = snd_kcontrol_chip(kcontrol); | ||
272 | int changed = 0; | ||
273 | |||
274 | if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) { | ||
275 | rt->digital_thru_switch = ucontrol->value.integer.value[0]; | ||
276 | usb6fire_control_streaming_update(rt); | ||
277 | changed = 1; | ||
278 | } | ||
279 | return changed; | ||
280 | } | ||
281 | |||
282 | static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol, | ||
283 | struct snd_ctl_elem_value *ucontrol) | ||
284 | { | ||
285 | struct control_runtime *rt = snd_kcontrol_chip(kcontrol); | ||
286 | ucontrol->value.integer.value[0] = rt->digital_thru_switch; | ||
287 | return 0; | ||
288 | } | ||
289 | |||
198 | static struct __devinitdata snd_kcontrol_new elements[] = { | 290 | static struct __devinitdata snd_kcontrol_new elements[] = { |
199 | { | 291 | { |
200 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 292 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -223,6 +315,15 @@ static struct __devinitdata snd_kcontrol_new elements[] = { | |||
223 | .get = usb6fire_control_opt_coax_get, | 315 | .get = usb6fire_control_opt_coax_get, |
224 | .put = usb6fire_control_opt_coax_put | 316 | .put = usb6fire_control_opt_coax_put |
225 | }, | 317 | }, |
318 | { | ||
319 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
320 | .name = "Digital Thru Playback Route", | ||
321 | .index = 0, | ||
322 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
323 | .info = snd_ctl_boolean_mono_info, | ||
324 | .get = usb6fire_control_digital_thru_get, | ||
325 | .put = usb6fire_control_digital_thru_put | ||
326 | }, | ||
226 | {} | 327 | {} |
227 | }; | 328 | }; |
228 | 329 | ||
@@ -238,6 +339,9 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) | |||
238 | return -ENOMEM; | 339 | return -ENOMEM; |
239 | 340 | ||
240 | rt->chip = chip; | 341 | rt->chip = chip; |
342 | rt->update_streaming = usb6fire_control_streaming_update; | ||
343 | rt->set_rate = usb6fire_control_set_rate; | ||
344 | rt->set_channels = usb6fire_control_set_channels; | ||
241 | 345 | ||
242 | i = 0; | 346 | i = 0; |
243 | while (init_data[i].type) { | 347 | while (init_data[i].type) { |
@@ -249,6 +353,7 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) | |||
249 | usb6fire_control_opt_coax_update(rt); | 353 | usb6fire_control_opt_coax_update(rt); |
250 | usb6fire_control_line_phono_update(rt); | 354 | usb6fire_control_line_phono_update(rt); |
251 | usb6fire_control_master_vol_update(rt); | 355 | usb6fire_control_master_vol_update(rt); |
356 | usb6fire_control_streaming_update(rt); | ||
252 | 357 | ||
253 | i = 0; | 358 | i = 0; |
254 | while (elements[i].name) { | 359 | while (elements[i].name) { |
diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h index b534c777ab02..8f5aeead2e3d 100644 --- a/sound/usb/6fire/control.h +++ b/sound/usb/6fire/control.h | |||
@@ -21,12 +21,29 @@ enum { | |||
21 | CONTROL_MAX_ELEMENTS = 32 | 21 | CONTROL_MAX_ELEMENTS = 32 |
22 | }; | 22 | }; |
23 | 23 | ||
24 | enum { | ||
25 | CONTROL_RATE_44KHZ, | ||
26 | CONTROL_RATE_48KHZ, | ||
27 | CONTROL_RATE_88KHZ, | ||
28 | CONTROL_RATE_96KHZ, | ||
29 | CONTROL_RATE_176KHZ, | ||
30 | CONTROL_RATE_192KHZ, | ||
31 | CONTROL_N_RATES | ||
32 | }; | ||
33 | |||
24 | struct control_runtime { | 34 | struct control_runtime { |
35 | int (*update_streaming)(struct control_runtime *rt); | ||
36 | int (*set_rate)(struct control_runtime *rt, int rate); | ||
37 | int (*set_channels)(struct control_runtime *rt, int n_analog_out, | ||
38 | int n_analog_in, bool spdif_out, bool spdif_in); | ||
39 | |||
25 | struct sfire_chip *chip; | 40 | struct sfire_chip *chip; |
26 | 41 | ||
27 | struct snd_kcontrol *element[CONTROL_MAX_ELEMENTS]; | 42 | struct snd_kcontrol *element[CONTROL_MAX_ELEMENTS]; |
28 | bool opt_coax_switch; | 43 | bool opt_coax_switch; |
29 | bool line_phono_switch; | 44 | bool line_phono_switch; |
45 | bool digital_thru_switch; | ||
46 | bool usb_streaming; | ||
30 | u8 master_vol; | 47 | u8 master_vol; |
31 | }; | 48 | }; |
32 | 49 | ||
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index 86c1a3103760..d47beffedb0f 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c | |||
@@ -3,12 +3,6 @@ | |||
3 | * | 3 | * |
4 | * Firmware loader | 4 | * Firmware loader |
5 | * | 5 | * |
6 | * Currently not working for all devices. To be able to use the device | ||
7 | * in linux, it is also possible to let the windows driver upload the firmware. | ||
8 | * For that, start the computer in windows and reboot. | ||
9 | * As long as the device is connected to the power supply, no firmware reload | ||
10 | * needs to be performed. | ||
11 | * | ||
12 | * Author: Torsten Schenk <torsten.schenk@zoho.com> | 6 | * Author: Torsten Schenk <torsten.schenk@zoho.com> |
13 | * Created: Jan 01, 2011 | 7 | * Created: Jan 01, 2011 |
14 | * Version: 0.3.0 | 8 | * Version: 0.3.0 |
@@ -21,6 +15,7 @@ | |||
21 | */ | 15 | */ |
22 | 16 | ||
23 | #include <linux/firmware.h> | 17 | #include <linux/firmware.h> |
18 | #include <linux/bitrev.h> | ||
24 | 19 | ||
25 | #include "firmware.h" | 20 | #include "firmware.h" |
26 | #include "chip.h" | 21 | #include "chip.h" |
@@ -33,32 +28,6 @@ enum { | |||
33 | FPGA_BUFSIZE = 512, FPGA_EP = 2 | 28 | FPGA_BUFSIZE = 512, FPGA_EP = 2 |
34 | }; | 29 | }; |
35 | 30 | ||
36 | static const u8 BIT_REVERSE_TABLE[256] = { | ||
37 | 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, | ||
38 | 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, | ||
39 | 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, | ||
40 | 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, | ||
41 | 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, | ||
42 | 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, | ||
43 | 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, | ||
44 | 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, | ||
45 | 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, | ||
46 | 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, | ||
47 | 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, | ||
48 | 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, | ||
49 | 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, | ||
50 | 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, | ||
51 | 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, | ||
52 | 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, | ||
53 | 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, | ||
54 | 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, | ||
55 | 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, | ||
56 | 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, | ||
57 | 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, | ||
58 | 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, | ||
59 | 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, | ||
60 | 0xbf, 0x7f, 0xff }; | ||
61 | |||
62 | /* | 31 | /* |
63 | * wMaxPacketSize of pcm endpoints. | 32 | * wMaxPacketSize of pcm endpoints. |
64 | * keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c | 33 | * keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c |
@@ -72,6 +41,10 @@ static const u8 ep_w_max_packet_size[] = { | |||
72 | 0x94, 0x01, 0x5c, 0x02 /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */ | 41 | 0x94, 0x01, 0x5c, 0x02 /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */ |
73 | }; | 42 | }; |
74 | 43 | ||
44 | static const u8 known_fw_versions[][4] = { | ||
45 | { 0x03, 0x01, 0x0b, 0x00 } | ||
46 | }; | ||
47 | |||
75 | struct ihex_record { | 48 | struct ihex_record { |
76 | u16 address; | 49 | u16 address; |
77 | u8 len; | 50 | u8 len; |
@@ -340,7 +313,7 @@ static int usb6fire_fw_fpga_upload( | |||
340 | 313 | ||
341 | while (c != end) { | 314 | while (c != end) { |
342 | for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++) | 315 | for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++) |
343 | buffer[i] = BIT_REVERSE_TABLE[(u8) *c]; | 316 | buffer[i] = byte_rev_table[(u8) *c]; |
344 | 317 | ||
345 | ret = usb6fire_fw_fpga_write(device, buffer, i); | 318 | ret = usb6fire_fw_fpga_write(device, buffer, i); |
346 | if (ret < 0) { | 319 | if (ret < 0) { |
@@ -363,6 +336,25 @@ static int usb6fire_fw_fpga_upload( | |||
363 | return 0; | 336 | return 0; |
364 | } | 337 | } |
365 | 338 | ||
339 | /* check, if the firmware version the devices has currently loaded | ||
340 | * is known by this driver. 'version' needs to have 4 bytes version | ||
341 | * info data. */ | ||
342 | static int usb6fire_fw_check(u8 *version) | ||
343 | { | ||
344 | int i; | ||
345 | |||
346 | for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++) | ||
347 | if (!memcmp(version, known_fw_versions + i, 4)) | ||
348 | return 0; | ||
349 | |||
350 | snd_printk(KERN_ERR PREFIX "invalid fimware version in device: " | ||
351 | "%02x %02x %02x %02x. " | ||
352 | "please reconnect to power. if this failure " | ||
353 | "still happens, check your firmware installation.", | ||
354 | version[0], version[1], version[2], version[3]); | ||
355 | return -EINVAL; | ||
356 | } | ||
357 | |||
366 | int usb6fire_fw_init(struct usb_interface *intf) | 358 | int usb6fire_fw_init(struct usb_interface *intf) |
367 | { | 359 | { |
368 | int i; | 360 | int i; |
@@ -378,9 +370,7 @@ int usb6fire_fw_init(struct usb_interface *intf) | |||
378 | "firmware state.\n"); | 370 | "firmware state.\n"); |
379 | return ret; | 371 | return ret; |
380 | } | 372 | } |
381 | if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55 | 373 | if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) { |
382 | || buffer[4] != 0x03 || buffer[5] != 0x01 || buffer[7] | ||
383 | != 0x00) { | ||
384 | snd_printk(KERN_ERR PREFIX "unknown device firmware state " | 374 | snd_printk(KERN_ERR PREFIX "unknown device firmware state " |
385 | "received from device: "); | 375 | "received from device: "); |
386 | for (i = 0; i < 8; i++) | 376 | for (i = 0; i < 8; i++) |
@@ -389,7 +379,7 @@ int usb6fire_fw_init(struct usb_interface *intf) | |||
389 | return -EIO; | 379 | return -EIO; |
390 | } | 380 | } |
391 | /* do we need fpga loader ezusb firmware? */ | 381 | /* do we need fpga loader ezusb firmware? */ |
392 | if (buffer[3] == 0x01 && buffer[6] == 0x19) { | 382 | if (buffer[3] == 0x01) { |
393 | ret = usb6fire_fw_ezusb_upload(intf, | 383 | ret = usb6fire_fw_ezusb_upload(intf, |
394 | "6fire/dmx6firel2.ihx", 0, NULL, 0); | 384 | "6fire/dmx6firel2.ihx", 0, NULL, 0); |
395 | if (ret < 0) | 385 | if (ret < 0) |
@@ -397,7 +387,10 @@ int usb6fire_fw_init(struct usb_interface *intf) | |||
397 | return FW_NOT_READY; | 387 | return FW_NOT_READY; |
398 | } | 388 | } |
399 | /* do we need fpga firmware and application ezusb firmware? */ | 389 | /* do we need fpga firmware and application ezusb firmware? */ |
400 | else if (buffer[3] == 0x02 && buffer[6] == 0x0b) { | 390 | else if (buffer[3] == 0x02) { |
391 | ret = usb6fire_fw_check(buffer + 4); | ||
392 | if (ret < 0) | ||
393 | return ret; | ||
401 | ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin"); | 394 | ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin"); |
402 | if (ret < 0) | 395 | if (ret < 0) |
403 | return ret; | 396 | return ret; |
@@ -410,8 +403,8 @@ int usb6fire_fw_init(struct usb_interface *intf) | |||
410 | return FW_NOT_READY; | 403 | return FW_NOT_READY; |
411 | } | 404 | } |
412 | /* all fw loaded? */ | 405 | /* all fw loaded? */ |
413 | else if (buffer[3] == 0x03 && buffer[6] == 0x0b) | 406 | else if (buffer[3] == 0x03) |
414 | return 0; | 407 | return usb6fire_fw_check(buffer + 4); |
415 | /* unknown data? */ | 408 | /* unknown data? */ |
416 | else { | 409 | else { |
417 | snd_printk(KERN_ERR PREFIX "unknown device firmware state " | 410 | snd_printk(KERN_ERR PREFIX "unknown device firmware state " |
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index ba62c7468ba8..b137b25865cc 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c | |||
@@ -17,26 +17,23 @@ | |||
17 | #include "pcm.h" | 17 | #include "pcm.h" |
18 | #include "chip.h" | 18 | #include "chip.h" |
19 | #include "comm.h" | 19 | #include "comm.h" |
20 | #include "control.h" | ||
20 | 21 | ||
21 | enum { | 22 | enum { |
22 | OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4 | 23 | OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4 |
23 | }; | 24 | }; |
24 | 25 | ||
25 | /* keep next two synced with | 26 | /* keep next two synced with |
26 | * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */ | 27 | * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE |
28 | * and CONTROL_RATE_XXX in control.h */ | ||
27 | static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 }; | 29 | static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 }; |
28 | static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 }; | 30 | static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 }; |
29 | static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; | 31 | static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; |
30 | static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 }; | ||
31 | static const int rates_alsaid[] = { | 32 | static const int rates_alsaid[] = { |
32 | SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000, | 33 | SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000, |
33 | SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000, | 34 | SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000, |
34 | SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 }; | 35 | SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 }; |
35 | 36 | ||
36 | /* values to write to soundcard register for all samplerates */ | ||
37 | static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; | ||
38 | static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; | ||
39 | |||
40 | enum { /* settings for pcm */ | 37 | enum { /* settings for pcm */ |
41 | OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024 | 38 | OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024 |
42 | }; | 39 | }; |
@@ -48,15 +45,6 @@ enum { /* pcm streaming states */ | |||
48 | STREAM_STOPPING | 45 | STREAM_STOPPING |
49 | }; | 46 | }; |
50 | 47 | ||
51 | enum { /* pcm sample rates (also index into RATES_XXX[]) */ | ||
52 | RATE_44KHZ, | ||
53 | RATE_48KHZ, | ||
54 | RATE_88KHZ, | ||
55 | RATE_96KHZ, | ||
56 | RATE_176KHZ, | ||
57 | RATE_192KHZ | ||
58 | }; | ||
59 | |||
60 | static const struct snd_pcm_hardware pcm_hw = { | 48 | static const struct snd_pcm_hardware pcm_hw = { |
61 | .info = SNDRV_PCM_INFO_MMAP | | 49 | .info = SNDRV_PCM_INFO_MMAP | |
62 | SNDRV_PCM_INFO_INTERLEAVED | | 50 | SNDRV_PCM_INFO_INTERLEAVED | |
@@ -64,7 +52,7 @@ static const struct snd_pcm_hardware pcm_hw = { | |||
64 | SNDRV_PCM_INFO_MMAP_VALID | | 52 | SNDRV_PCM_INFO_MMAP_VALID | |
65 | SNDRV_PCM_INFO_BATCH, | 53 | SNDRV_PCM_INFO_BATCH, |
66 | 54 | ||
67 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | 55 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, |
68 | 56 | ||
69 | .rates = SNDRV_PCM_RATE_44100 | | 57 | .rates = SNDRV_PCM_RATE_44100 | |
70 | SNDRV_PCM_RATE_48000 | | 58 | SNDRV_PCM_RATE_48000 | |
@@ -87,57 +75,34 @@ static const struct snd_pcm_hardware pcm_hw = { | |||
87 | static int usb6fire_pcm_set_rate(struct pcm_runtime *rt) | 75 | static int usb6fire_pcm_set_rate(struct pcm_runtime *rt) |
88 | { | 76 | { |
89 | int ret; | 77 | int ret; |
90 | struct usb_device *device = rt->chip->dev; | 78 | struct control_runtime *ctrl_rt = rt->chip->control; |
91 | struct comm_runtime *comm_rt = rt->chip->comm; | ||
92 | 79 | ||
93 | if (rt->rate >= ARRAY_SIZE(rates)) | 80 | ctrl_rt->usb_streaming = false; |
94 | return -EINVAL; | 81 | ret = ctrl_rt->update_streaming(ctrl_rt); |
95 | /* disable streaming */ | ||
96 | ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x00); | ||
97 | if (ret < 0) { | 82 | if (ret < 0) { |
98 | snd_printk(KERN_ERR PREFIX "error stopping streaming while " | 83 | snd_printk(KERN_ERR PREFIX "error stopping streaming while " |
99 | "setting samplerate %d.\n", rates[rt->rate]); | 84 | "setting samplerate %d.\n", rates[rt->rate]); |
100 | return ret; | 85 | return ret; |
101 | } | 86 | } |
102 | 87 | ||
103 | ret = usb_set_interface(device, 1, rates_altsetting[rt->rate]); | 88 | ret = ctrl_rt->set_rate(ctrl_rt, rt->rate); |
104 | if (ret < 0) { | ||
105 | snd_printk(KERN_ERR PREFIX "error setting interface " | ||
106 | "altsetting %d for samplerate %d.\n", | ||
107 | rates_altsetting[rt->rate], rates[rt->rate]); | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | /* set soundcard clock */ | ||
112 | ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rt->rate], | ||
113 | rates_6fire_vh[rt->rate]); | ||
114 | if (ret < 0) { | 89 | if (ret < 0) { |
115 | snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n", | 90 | snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n", |
116 | rates[rt->rate]); | 91 | rates[rt->rate]); |
117 | return ret; | 92 | return ret; |
118 | } | 93 | } |
119 | 94 | ||
120 | /* enable analog inputs and outputs | 95 | ret = ctrl_rt->set_channels(ctrl_rt, OUT_N_CHANNELS, IN_N_CHANNELS, |
121 | * (one bit per stereo-channel) */ | 96 | false, false); |
122 | ret = comm_rt->write16(comm_rt, 0x02, 0x02, | ||
123 | (1 << (OUT_N_CHANNELS / 2)) - 1, | ||
124 | (1 << (IN_N_CHANNELS / 2)) - 1); | ||
125 | if (ret < 0) { | 97 | if (ret < 0) { |
126 | snd_printk(KERN_ERR PREFIX "error initializing analog channels " | 98 | snd_printk(KERN_ERR PREFIX "error initializing channels " |
127 | "while setting samplerate %d.\n", | 99 | "while setting samplerate %d.\n", |
128 | rates[rt->rate]); | 100 | rates[rt->rate]); |
129 | return ret; | 101 | return ret; |
130 | } | 102 | } |
131 | /* disable digital inputs and outputs */ | ||
132 | ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00); | ||
133 | if (ret < 0) { | ||
134 | snd_printk(KERN_ERR PREFIX "error initializing digital " | ||
135 | "channels while setting samplerate %d.\n", | ||
136 | rates[rt->rate]); | ||
137 | return ret; | ||
138 | } | ||
139 | 103 | ||
140 | ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x01); | 104 | ctrl_rt->usb_streaming = true; |
105 | ret = ctrl_rt->update_streaming(ctrl_rt); | ||
141 | if (ret < 0) { | 106 | if (ret < 0) { |
142 | snd_printk(KERN_ERR PREFIX "error starting streaming while " | 107 | snd_printk(KERN_ERR PREFIX "error starting streaming while " |
143 | "setting samplerate %d.\n", rates[rt->rate]); | 108 | "setting samplerate %d.\n", rates[rt->rate]); |
@@ -168,12 +133,15 @@ static struct pcm_substream *usb6fire_pcm_get_substream( | |||
168 | static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt) | 133 | static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt) |
169 | { | 134 | { |
170 | int i; | 135 | int i; |
136 | struct control_runtime *ctrl_rt = rt->chip->control; | ||
171 | 137 | ||
172 | if (rt->stream_state != STREAM_DISABLED) { | 138 | if (rt->stream_state != STREAM_DISABLED) { |
173 | for (i = 0; i < PCM_N_URBS; i++) { | 139 | for (i = 0; i < PCM_N_URBS; i++) { |
174 | usb_kill_urb(&rt->in_urbs[i].instance); | 140 | usb_kill_urb(&rt->in_urbs[i].instance); |
175 | usb_kill_urb(&rt->out_urbs[i].instance); | 141 | usb_kill_urb(&rt->out_urbs[i].instance); |
176 | } | 142 | } |
143 | ctrl_rt->usb_streaming = false; | ||
144 | ctrl_rt->update_streaming(ctrl_rt); | ||
177 | rt->stream_state = STREAM_DISABLED; | 145 | rt->stream_state = STREAM_DISABLED; |
178 | } | 146 | } |
179 | } | 147 | } |
@@ -228,7 +196,7 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) | |||
228 | unsigned int total_length = 0; | 196 | unsigned int total_length = 0; |
229 | struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance); | 197 | struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance); |
230 | struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; | 198 | struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; |
231 | u32 *src = (u32 *) urb->buffer; | 199 | u32 *src = NULL; |
232 | u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off | 200 | u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off |
233 | * (alsa_rt->frame_bits >> 3)); | 201 | * (alsa_rt->frame_bits >> 3)); |
234 | u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size | 202 | u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size |
@@ -244,7 +212,12 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) | |||
244 | else | 212 | else |
245 | frame_count = 0; | 213 | frame_count = 0; |
246 | 214 | ||
247 | src = (u32 *) (urb->buffer + total_length); | 215 | if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE) |
216 | src = (u32 *) (urb->buffer + total_length); | ||
217 | else if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE) | ||
218 | src = (u32 *) (urb->buffer - 1 + total_length); | ||
219 | else | ||
220 | return; | ||
248 | src++; /* skip leading 4 bytes of every packet */ | 221 | src++; /* skip leading 4 bytes of every packet */ |
249 | total_length += urb->packets[i].length; | 222 | total_length += urb->packets[i].length; |
250 | for (frame = 0; frame < frame_count; frame++) { | 223 | for (frame = 0; frame < frame_count; frame++) { |
@@ -274,9 +247,18 @@ static void usb6fire_pcm_playback(struct pcm_substream *sub, | |||
274 | * (alsa_rt->frame_bits >> 3)); | 247 | * (alsa_rt->frame_bits >> 3)); |
275 | u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size | 248 | u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size |
276 | * (alsa_rt->frame_bits >> 3)); | 249 | * (alsa_rt->frame_bits >> 3)); |
277 | u32 *dest = (u32 *) urb->buffer; | 250 | u32 *dest; |
278 | int bytes_per_frame = alsa_rt->channels << 2; | 251 | int bytes_per_frame = alsa_rt->channels << 2; |
279 | 252 | ||
253 | if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE) | ||
254 | dest = (u32 *) (urb->buffer - 1); | ||
255 | else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE) | ||
256 | dest = (u32 *) (urb->buffer); | ||
257 | else { | ||
258 | snd_printk(KERN_ERR PREFIX "Unknown sample format."); | ||
259 | return; | ||
260 | } | ||
261 | |||
280 | for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { | 262 | for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { |
281 | /* at least 4 header bytes for valid packet. | 263 | /* at least 4 header bytes for valid packet. |
282 | * after that: 32 bits per sample for analog channels */ | 264 | * after that: 32 bits per sample for analog channels */ |
@@ -456,7 +438,7 @@ static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub) | |||
456 | /* all substreams closed? if so, stop streaming */ | 438 | /* all substreams closed? if so, stop streaming */ |
457 | if (!rt->playback.instance && !rt->capture.instance) { | 439 | if (!rt->playback.instance && !rt->capture.instance) { |
458 | usb6fire_pcm_stream_stop(rt); | 440 | usb6fire_pcm_stream_stop(rt); |
459 | rt->rate = -1; | 441 | rt->rate = ARRAY_SIZE(rates); |
460 | } | 442 | } |
461 | } | 443 | } |
462 | mutex_unlock(&rt->stream_mutex); | 444 | mutex_unlock(&rt->stream_mutex); |
@@ -480,7 +462,6 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) | |||
480 | struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); | 462 | struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); |
481 | struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); | 463 | struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); |
482 | struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; | 464 | struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; |
483 | int i; | ||
484 | int ret; | 465 | int ret; |
485 | 466 | ||
486 | if (rt->panic) | 467 | if (rt->panic) |
@@ -493,12 +474,10 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) | |||
493 | sub->period_off = 0; | 474 | sub->period_off = 0; |
494 | 475 | ||
495 | if (rt->stream_state == STREAM_DISABLED) { | 476 | if (rt->stream_state == STREAM_DISABLED) { |
496 | for (i = 0; i < ARRAY_SIZE(rates); i++) | 477 | for (rt->rate = 0; rt->rate < ARRAY_SIZE(rates); rt->rate++) |
497 | if (alsa_rt->rate == rates[i]) { | 478 | if (alsa_rt->rate == rates[rt->rate]) |
498 | rt->rate = i; | ||
499 | break; | 479 | break; |
500 | } | 480 | if (rt->rate == ARRAY_SIZE(rates)) { |
501 | if (i == ARRAY_SIZE(rates)) { | ||
502 | mutex_unlock(&rt->stream_mutex); | 481 | mutex_unlock(&rt->stream_mutex); |
503 | snd_printk("invalid rate %d in prepare.\n", | 482 | snd_printk("invalid rate %d in prepare.\n", |
504 | alsa_rt->rate); | 483 | alsa_rt->rate); |
@@ -613,7 +592,7 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip) | |||
613 | 592 | ||
614 | rt->chip = chip; | 593 | rt->chip = chip; |
615 | rt->stream_state = STREAM_DISABLED; | 594 | rt->stream_state = STREAM_DISABLED; |
616 | rt->rate = -1; | 595 | rt->rate = ARRAY_SIZE(rates); |
617 | init_waitqueue_head(&rt->stream_wait_queue); | 596 | init_waitqueue_head(&rt->stream_wait_queue); |
618 | mutex_init(&rt->stream_mutex); | 597 | mutex_init(&rt->stream_mutex); |
619 | 598 | ||