0001
0002
0003
0004
0005
0006 #include <linux/virtio_config.h>
0007 #include <sound/jack.h>
0008 #include <sound/hda_verbs.h>
0009
0010 #include "virtio_card.h"
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 struct virtio_jack {
0033 struct snd_jack *jack;
0034 u32 nid;
0035 u32 features;
0036 u32 defconf;
0037 u32 caps;
0038 bool connected;
0039 int type;
0040 };
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052 static const char *virtsnd_jack_get_label(struct virtio_jack *vjack)
0053 {
0054 unsigned int defconf = vjack->defconf;
0055 unsigned int device =
0056 (defconf & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT;
0057 unsigned int location =
0058 (defconf & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
0059
0060 switch (device) {
0061 case AC_JACK_LINE_OUT:
0062 return "Line Out";
0063 case AC_JACK_SPEAKER:
0064 return "Speaker";
0065 case AC_JACK_HP_OUT:
0066 return "Headphone";
0067 case AC_JACK_CD:
0068 return "CD";
0069 case AC_JACK_SPDIF_OUT:
0070 case AC_JACK_DIG_OTHER_OUT:
0071 if (location == AC_JACK_LOC_HDMI)
0072 return "HDMI Out";
0073 else
0074 return "SPDIF Out";
0075 case AC_JACK_LINE_IN:
0076 return "Line";
0077 case AC_JACK_AUX:
0078 return "Aux";
0079 case AC_JACK_MIC_IN:
0080 return "Mic";
0081 case AC_JACK_SPDIF_IN:
0082 return "SPDIF In";
0083 case AC_JACK_DIG_OTHER_IN:
0084 return "Digital In";
0085 default:
0086 return "Misc";
0087 }
0088 }
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 static int virtsnd_jack_get_type(struct virtio_jack *vjack)
0101 {
0102 unsigned int defconf = vjack->defconf;
0103 unsigned int device =
0104 (defconf & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT;
0105
0106 switch (device) {
0107 case AC_JACK_LINE_OUT:
0108 case AC_JACK_SPEAKER:
0109 return SND_JACK_LINEOUT;
0110 case AC_JACK_HP_OUT:
0111 return SND_JACK_HEADPHONE;
0112 case AC_JACK_SPDIF_OUT:
0113 case AC_JACK_DIG_OTHER_OUT:
0114 return SND_JACK_AVOUT;
0115 case AC_JACK_MIC_IN:
0116 return SND_JACK_MICROPHONE;
0117 default:
0118 return SND_JACK_LINEIN;
0119 }
0120 }
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131 int virtsnd_jack_parse_cfg(struct virtio_snd *snd)
0132 {
0133 struct virtio_device *vdev = snd->vdev;
0134 struct virtio_snd_jack_info *info;
0135 u32 i;
0136 int rc;
0137
0138 virtio_cread_le(vdev, struct virtio_snd_config, jacks, &snd->njacks);
0139 if (!snd->njacks)
0140 return 0;
0141
0142 snd->jacks = devm_kcalloc(&vdev->dev, snd->njacks, sizeof(*snd->jacks),
0143 GFP_KERNEL);
0144 if (!snd->jacks)
0145 return -ENOMEM;
0146
0147 info = kcalloc(snd->njacks, sizeof(*info), GFP_KERNEL);
0148 if (!info)
0149 return -ENOMEM;
0150
0151 rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_JACK_INFO, 0, snd->njacks,
0152 sizeof(*info), info);
0153 if (rc)
0154 goto on_exit;
0155
0156 for (i = 0; i < snd->njacks; ++i) {
0157 struct virtio_jack *vjack = &snd->jacks[i];
0158
0159 vjack->nid = le32_to_cpu(info[i].hdr.hda_fn_nid);
0160 vjack->features = le32_to_cpu(info[i].features);
0161 vjack->defconf = le32_to_cpu(info[i].hda_reg_defconf);
0162 vjack->caps = le32_to_cpu(info[i].hda_reg_caps);
0163 vjack->connected = info[i].connected;
0164 }
0165
0166 on_exit:
0167 kfree(info);
0168
0169 return rc;
0170 }
0171
0172
0173
0174
0175
0176
0177
0178
0179 int virtsnd_jack_build_devs(struct virtio_snd *snd)
0180 {
0181 u32 i;
0182 int rc;
0183
0184 for (i = 0; i < snd->njacks; ++i) {
0185 struct virtio_jack *vjack = &snd->jacks[i];
0186
0187 vjack->type = virtsnd_jack_get_type(vjack);
0188
0189 rc = snd_jack_new(snd->card, virtsnd_jack_get_label(vjack),
0190 vjack->type, &vjack->jack, true, true);
0191 if (rc)
0192 return rc;
0193
0194 if (vjack->jack)
0195 vjack->jack->private_data = vjack;
0196
0197 snd_jack_report(vjack->jack,
0198 vjack->connected ? vjack->type : 0);
0199 }
0200
0201 return 0;
0202 }
0203
0204
0205
0206
0207
0208
0209
0210
0211 void virtsnd_jack_event(struct virtio_snd *snd, struct virtio_snd_event *event)
0212 {
0213 u32 jack_id = le32_to_cpu(event->data);
0214 struct virtio_jack *vjack;
0215
0216 if (jack_id >= snd->njacks)
0217 return;
0218
0219 vjack = &snd->jacks[jack_id];
0220
0221 switch (le32_to_cpu(event->hdr.code)) {
0222 case VIRTIO_SND_EVT_JACK_CONNECTED:
0223 vjack->connected = true;
0224 break;
0225 case VIRTIO_SND_EVT_JACK_DISCONNECTED:
0226 vjack->connected = false;
0227 break;
0228 default:
0229 return;
0230 }
0231
0232 snd_jack_report(vjack->jack, vjack->connected ? vjack->type : 0);
0233 }