diff options
-rw-r--r-- | sound/firewire/oxfw/Makefile | 2 | ||||
-rw-r--r-- | sound/firewire/oxfw/oxfw-command.c | 153 | ||||
-rw-r--r-- | sound/firewire/oxfw/oxfw.h | 33 |
3 files changed, 187 insertions, 1 deletions
diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile index 0cf48fd87688..b107134d11d5 100644 --- a/sound/firewire/oxfw/Makefile +++ b/sound/firewire/oxfw/Makefile | |||
@@ -1,2 +1,2 @@ | |||
1 | snd-oxfw-objs := oxfw-stream.o oxfw-control.o oxfw-pcm.o oxfw.o | 1 | snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-control.o oxfw-pcm.o oxfw.o |
2 | obj-m += snd-oxfw.o | 2 | obj-m += snd-oxfw.o |
diff --git a/sound/firewire/oxfw/oxfw-command.c b/sound/firewire/oxfw/oxfw-command.c new file mode 100644 index 000000000000..12ef3253bc89 --- /dev/null +++ b/sound/firewire/oxfw/oxfw-command.c | |||
@@ -0,0 +1,153 @@ | |||
1 | /* | ||
2 | * oxfw_command.c - a part of driver for OXFW970/971 based devices | ||
3 | * | ||
4 | * Copyright (c) 2014 Takashi Sakamoto | ||
5 | * | ||
6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
7 | */ | ||
8 | |||
9 | #include "oxfw.h" | ||
10 | |||
11 | int avc_stream_set_format(struct fw_unit *unit, enum avc_general_plug_dir dir, | ||
12 | unsigned int pid, u8 *format, unsigned int len) | ||
13 | { | ||
14 | u8 *buf; | ||
15 | int err; | ||
16 | |||
17 | buf = kmalloc(len + 10, GFP_KERNEL); | ||
18 | if (buf == NULL) | ||
19 | return -ENOMEM; | ||
20 | |||
21 | buf[0] = 0x00; /* CONTROL */ | ||
22 | buf[1] = 0xff; /* UNIT */ | ||
23 | buf[2] = 0xbf; /* EXTENDED STREAM FORMAT INFORMATION */ | ||
24 | buf[3] = 0xc0; /* SINGLE subfunction */ | ||
25 | buf[4] = dir; /* Plug Direction */ | ||
26 | buf[5] = 0x00; /* UNIT */ | ||
27 | buf[6] = 0x00; /* PCR (Isochronous Plug) */ | ||
28 | buf[7] = 0xff & pid; /* Plug ID */ | ||
29 | buf[8] = 0xff; /* Padding */ | ||
30 | buf[9] = 0xff; /* Support status in response */ | ||
31 | memcpy(buf + 10, format, len); | ||
32 | |||
33 | /* do transaction and check buf[1-8] are the same against command */ | ||
34 | err = fcp_avc_transaction(unit, buf, len + 10, buf, len + 10, | ||
35 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | | ||
36 | BIT(6) | BIT(7) | BIT(8)); | ||
37 | if ((err > 0) && (err < len + 10)) | ||
38 | err = -EIO; | ||
39 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | ||
40 | err = -ENOSYS; | ||
41 | else if (buf[0] == 0x0a) /* REJECTED */ | ||
42 | err = -EINVAL; | ||
43 | else | ||
44 | err = 0; | ||
45 | |||
46 | kfree(buf); | ||
47 | |||
48 | return err; | ||
49 | } | ||
50 | |||
51 | int avc_stream_get_format(struct fw_unit *unit, | ||
52 | enum avc_general_plug_dir dir, unsigned int pid, | ||
53 | u8 *buf, unsigned int *len, unsigned int eid) | ||
54 | { | ||
55 | unsigned int subfunc; | ||
56 | int err; | ||
57 | |||
58 | if (eid == 0xff) | ||
59 | subfunc = 0xc0; /* SINGLE */ | ||
60 | else | ||
61 | subfunc = 0xc1; /* LIST */ | ||
62 | |||
63 | buf[0] = 0x01; /* STATUS */ | ||
64 | buf[1] = 0xff; /* UNIT */ | ||
65 | buf[2] = 0xbf; /* EXTENDED STREAM FORMAT INFORMATION */ | ||
66 | buf[3] = subfunc; /* SINGLE or LIST */ | ||
67 | buf[4] = dir; /* Plug Direction */ | ||
68 | buf[5] = 0x00; /* Unit */ | ||
69 | buf[6] = 0x00; /* PCR (Isochronous Plug) */ | ||
70 | buf[7] = 0xff & pid; /* Plug ID */ | ||
71 | buf[8] = 0xff; /* Padding */ | ||
72 | buf[9] = 0xff; /* support status in response */ | ||
73 | buf[10] = 0xff & eid; /* entry ID for LIST subfunction */ | ||
74 | buf[11] = 0xff; /* padding */ | ||
75 | |||
76 | /* do transaction and check buf[1-7] are the same against command */ | ||
77 | err = fcp_avc_transaction(unit, buf, 12, buf, *len, | ||
78 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | | ||
79 | BIT(6) | BIT(7)); | ||
80 | if ((err > 0) && (err < 10)) | ||
81 | err = -EIO; | ||
82 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | ||
83 | err = -ENOSYS; | ||
84 | else if (buf[0] == 0x0a) /* REJECTED */ | ||
85 | err = -EINVAL; | ||
86 | else if (buf[0] == 0x0b) /* IN TRANSITION */ | ||
87 | err = -EAGAIN; | ||
88 | /* LIST subfunction has entry ID */ | ||
89 | else if ((subfunc == 0xc1) && (buf[10] != eid)) | ||
90 | err = -EIO; | ||
91 | if (err < 0) | ||
92 | goto end; | ||
93 | |||
94 | /* keep just stream format information */ | ||
95 | if (subfunc == 0xc0) { | ||
96 | memmove(buf, buf + 10, err - 10); | ||
97 | *len = err - 10; | ||
98 | } else { | ||
99 | memmove(buf, buf + 11, err - 11); | ||
100 | *len = err - 11; | ||
101 | } | ||
102 | |||
103 | err = 0; | ||
104 | end: | ||
105 | return err; | ||
106 | } | ||
107 | |||
108 | int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate, | ||
109 | enum avc_general_plug_dir dir, | ||
110 | unsigned short pid) | ||
111 | { | ||
112 | unsigned int sfc; | ||
113 | u8 *buf; | ||
114 | int err; | ||
115 | |||
116 | for (sfc = 0; sfc < CIP_SFC_COUNT; sfc++) { | ||
117 | if (amdtp_rate_table[sfc] == rate) | ||
118 | break; | ||
119 | } | ||
120 | if (sfc == CIP_SFC_COUNT) | ||
121 | return -EINVAL; | ||
122 | |||
123 | buf = kzalloc(8, GFP_KERNEL); | ||
124 | if (buf == NULL) | ||
125 | return -ENOMEM; | ||
126 | |||
127 | buf[0] = 0x02; /* SPECIFIC INQUIRY */ | ||
128 | buf[1] = 0xff; /* UNIT */ | ||
129 | if (dir == AVC_GENERAL_PLUG_DIR_IN) | ||
130 | buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */ | ||
131 | else | ||
132 | buf[2] = 0x18; /* OUTPUT PLUG SIGNAL FORMAT */ | ||
133 | buf[3] = 0xff & pid; /* plug id */ | ||
134 | buf[4] = 0x90; /* EOH_1, Form_1, FMT. AM824 */ | ||
135 | buf[5] = 0x07 & sfc; /* FDF-hi. AM824, frequency */ | ||
136 | buf[6] = 0xff; /* FDF-mid. AM824, SYT hi (not used) */ | ||
137 | buf[7] = 0xff; /* FDF-low. AM824, SYT lo (not used) */ | ||
138 | |||
139 | /* do transaction and check buf[1-5] are the same against command */ | ||
140 | err = fcp_avc_transaction(unit, buf, 8, buf, 8, | ||
141 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5)); | ||
142 | if ((err > 0) && (err < 8)) | ||
143 | err = -EIO; | ||
144 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | ||
145 | err = -ENOSYS; | ||
146 | if (err < 0) | ||
147 | goto end; | ||
148 | |||
149 | err = 0; | ||
150 | end: | ||
151 | kfree(buf); | ||
152 | return err; | ||
153 | } | ||
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index a61c75cbaba8..a7031d414441 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h | |||
@@ -49,6 +49,39 @@ struct snd_oxfw { | |||
49 | s16 volume_max; | 49 | s16 volume_max; |
50 | }; | 50 | }; |
51 | 51 | ||
52 | /* | ||
53 | * AV/C Stream Format Information Specification 1.1 Working Draft | ||
54 | * (Apr 2005, 1394TA) | ||
55 | */ | ||
56 | int avc_stream_set_format(struct fw_unit *unit, enum avc_general_plug_dir dir, | ||
57 | unsigned int pid, u8 *format, unsigned int len); | ||
58 | int avc_stream_get_format(struct fw_unit *unit, | ||
59 | enum avc_general_plug_dir dir, unsigned int pid, | ||
60 | u8 *buf, unsigned int *len, unsigned int eid); | ||
61 | static inline int | ||
62 | avc_stream_get_format_single(struct fw_unit *unit, | ||
63 | enum avc_general_plug_dir dir, unsigned int pid, | ||
64 | u8 *buf, unsigned int *len) | ||
65 | { | ||
66 | return avc_stream_get_format(unit, dir, pid, buf, len, 0xff); | ||
67 | } | ||
68 | static inline int | ||
69 | avc_stream_get_format_list(struct fw_unit *unit, | ||
70 | enum avc_general_plug_dir dir, unsigned int pid, | ||
71 | u8 *buf, unsigned int *len, | ||
72 | unsigned int eid) | ||
73 | { | ||
74 | return avc_stream_get_format(unit, dir, pid, buf, len, eid); | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * AV/C Digital Interface Command Set General Specification 4.2 | ||
79 | * (Sep 2004, 1394TA) | ||
80 | */ | ||
81 | int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate, | ||
82 | enum avc_general_plug_dir dir, | ||
83 | unsigned short pid); | ||
84 | |||
52 | int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw); | 85 | int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw); |
53 | int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw); | 86 | int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw); |
54 | void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw); | 87 | void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw); |