diff options
| author | Takashi Iwai <tiwai@suse.de> | 2015-03-23 08:14:02 -0400 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2015-03-23 08:14:02 -0400 |
| commit | 3372dbdd8ca11f51be8c6a30b2bc79eb04c4a902 (patch) | |
| tree | d4499bf5a5665b4820ffaf96bce55bf6b895195e /sound/core | |
| parent | bc465aa9d045feb0e13b4a8f32cc33c1943f62d6 (diff) | |
| parent | 967b1307b69b8ada8b331e01046ad1ef83742e99 (diff) | |
Merge branch 'for-next' into topic/hda-core
Diffstat (limited to 'sound/core')
29 files changed, 553 insertions, 768 deletions
diff --git a/sound/core/control.c b/sound/core/control.c index eeb691d1911f..d677c27746e9 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
| @@ -192,36 +192,41 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, | |||
| 192 | EXPORT_SYMBOL(snd_ctl_notify); | 192 | EXPORT_SYMBOL(snd_ctl_notify); |
| 193 | 193 | ||
| 194 | /** | 194 | /** |
| 195 | * snd_ctl_new - create a control instance from the template | 195 | * snd_ctl_new - create a new control instance with some elements |
| 196 | * @control: the control template | 196 | * @kctl: the pointer to store new control instance |
| 197 | * @access: the default control access | 197 | * @count: the number of elements in this control |
| 198 | * @access: the default access flags for elements in this control | ||
| 199 | * @file: given when locking these elements | ||
| 198 | * | 200 | * |
| 199 | * Allocates a new struct snd_kcontrol instance and copies the given template | 201 | * Allocates a memory object for a new control instance. The instance has |
| 200 | * to the new instance. It does not copy volatile data (access). | 202 | * elements as many as the given number (@count). Each element has given |
| 203 | * access permissions (@access). Each element is locked when @file is given. | ||
| 201 | * | 204 | * |
| 202 | * Return: The pointer of the new instance, or %NULL on failure. | 205 | * Return: 0 on success, error code on failure |
| 203 | */ | 206 | */ |
| 204 | static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, | 207 | static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count, |
| 205 | unsigned int access) | 208 | unsigned int access, struct snd_ctl_file *file) |
| 206 | { | 209 | { |
| 207 | struct snd_kcontrol *kctl; | 210 | unsigned int size; |
| 208 | unsigned int idx; | 211 | unsigned int idx; |
| 209 | 212 | ||
| 210 | if (snd_BUG_ON(!control || !control->count)) | 213 | if (count == 0 || count > MAX_CONTROL_COUNT) |
| 211 | return NULL; | 214 | return -EINVAL; |
| 212 | 215 | ||
| 213 | if (control->count > MAX_CONTROL_COUNT) | 216 | size = sizeof(struct snd_kcontrol); |
| 214 | return NULL; | 217 | size += sizeof(struct snd_kcontrol_volatile) * count; |
| 215 | 218 | ||
| 216 | kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL); | 219 | *kctl = kzalloc(size, GFP_KERNEL); |
| 217 | if (kctl == NULL) { | 220 | if (!*kctl) |
| 218 | pr_err("ALSA: Cannot allocate control instance\n"); | 221 | return -ENOMEM; |
| 219 | return NULL; | 222 | |
| 223 | for (idx = 0; idx < count; idx++) { | ||
| 224 | (*kctl)->vd[idx].access = access; | ||
| 225 | (*kctl)->vd[idx].owner = file; | ||
| 220 | } | 226 | } |
| 221 | *kctl = *control; | 227 | (*kctl)->count = count; |
| 222 | for (idx = 0; idx < kctl->count; idx++) | 228 | |
| 223 | kctl->vd[idx].access = access; | 229 | return 0; |
| 224 | return kctl; | ||
| 225 | } | 230 | } |
| 226 | 231 | ||
| 227 | /** | 232 | /** |
| @@ -238,37 +243,53 @@ static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, | |||
| 238 | struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, | 243 | struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, |
| 239 | void *private_data) | 244 | void *private_data) |
| 240 | { | 245 | { |
| 241 | struct snd_kcontrol kctl; | 246 | struct snd_kcontrol *kctl; |
| 247 | unsigned int count; | ||
| 242 | unsigned int access; | 248 | unsigned int access; |
| 249 | int err; | ||
| 243 | 250 | ||
| 244 | if (snd_BUG_ON(!ncontrol || !ncontrol->info)) | 251 | if (snd_BUG_ON(!ncontrol || !ncontrol->info)) |
| 245 | return NULL; | 252 | return NULL; |
| 246 | memset(&kctl, 0, sizeof(kctl)); | 253 | |
| 247 | kctl.id.iface = ncontrol->iface; | 254 | count = ncontrol->count; |
| 248 | kctl.id.device = ncontrol->device; | 255 | if (count == 0) |
| 249 | kctl.id.subdevice = ncontrol->subdevice; | 256 | count = 1; |
| 257 | |||
| 258 | access = ncontrol->access; | ||
| 259 | if (access == 0) | ||
| 260 | access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
| 261 | access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
| 262 | SNDRV_CTL_ELEM_ACCESS_VOLATILE | | ||
| 263 | SNDRV_CTL_ELEM_ACCESS_INACTIVE | | ||
| 264 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE | | ||
| 265 | SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND | | ||
| 266 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK); | ||
| 267 | |||
| 268 | err = snd_ctl_new(&kctl, count, access, NULL); | ||
| 269 | if (err < 0) | ||
| 270 | return NULL; | ||
| 271 | |||
| 272 | /* The 'numid' member is decided when calling snd_ctl_add(). */ | ||
| 273 | kctl->id.iface = ncontrol->iface; | ||
| 274 | kctl->id.device = ncontrol->device; | ||
| 275 | kctl->id.subdevice = ncontrol->subdevice; | ||
| 250 | if (ncontrol->name) { | 276 | if (ncontrol->name) { |
| 251 | strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name)); | 277 | strlcpy(kctl->id.name, ncontrol->name, sizeof(kctl->id.name)); |
| 252 | if (strcmp(ncontrol->name, kctl.id.name) != 0) | 278 | if (strcmp(ncontrol->name, kctl->id.name) != 0) |
| 253 | pr_warn("ALSA: Control name '%s' truncated to '%s'\n", | 279 | pr_warn("ALSA: Control name '%s' truncated to '%s'\n", |
| 254 | ncontrol->name, kctl.id.name); | 280 | ncontrol->name, kctl->id.name); |
| 255 | } | 281 | } |
| 256 | kctl.id.index = ncontrol->index; | 282 | kctl->id.index = ncontrol->index; |
| 257 | kctl.count = ncontrol->count ? ncontrol->count : 1; | 283 | |
| 258 | access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : | 284 | kctl->info = ncontrol->info; |
| 259 | (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| | 285 | kctl->get = ncontrol->get; |
| 260 | SNDRV_CTL_ELEM_ACCESS_VOLATILE| | 286 | kctl->put = ncontrol->put; |
| 261 | SNDRV_CTL_ELEM_ACCESS_INACTIVE| | 287 | kctl->tlv.p = ncontrol->tlv.p; |
| 262 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE| | 288 | |
| 263 | SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND| | 289 | kctl->private_value = ncontrol->private_value; |
| 264 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)); | 290 | kctl->private_data = private_data; |
| 265 | kctl.info = ncontrol->info; | 291 | |
| 266 | kctl.get = ncontrol->get; | 292 | return kctl; |
| 267 | kctl.put = ncontrol->put; | ||
| 268 | kctl.tlv.p = ncontrol->tlv.p; | ||
| 269 | kctl.private_value = ncontrol->private_value; | ||
| 270 | kctl.private_data = private_data; | ||
| 271 | return snd_ctl_new(&kctl, access); | ||
| 272 | } | 293 | } |
| 273 | EXPORT_SYMBOL(snd_ctl_new1); | 294 | EXPORT_SYMBOL(snd_ctl_new1); |
| 274 | 295 | ||
| @@ -1161,84 +1182,102 @@ static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol) | |||
| 1161 | static int snd_ctl_elem_add(struct snd_ctl_file *file, | 1182 | static int snd_ctl_elem_add(struct snd_ctl_file *file, |
| 1162 | struct snd_ctl_elem_info *info, int replace) | 1183 | struct snd_ctl_elem_info *info, int replace) |
| 1163 | { | 1184 | { |
| 1185 | /* The capacity of struct snd_ctl_elem_value.value.*/ | ||
| 1186 | static const unsigned int value_sizes[] = { | ||
| 1187 | [SNDRV_CTL_ELEM_TYPE_BOOLEAN] = sizeof(long), | ||
| 1188 | [SNDRV_CTL_ELEM_TYPE_INTEGER] = sizeof(long), | ||
| 1189 | [SNDRV_CTL_ELEM_TYPE_ENUMERATED] = sizeof(unsigned int), | ||
| 1190 | [SNDRV_CTL_ELEM_TYPE_BYTES] = sizeof(unsigned char), | ||
| 1191 | [SNDRV_CTL_ELEM_TYPE_IEC958] = sizeof(struct snd_aes_iec958), | ||
| 1192 | [SNDRV_CTL_ELEM_TYPE_INTEGER64] = sizeof(long long), | ||
| 1193 | }; | ||
| 1194 | static const unsigned int max_value_counts[] = { | ||
| 1195 | [SNDRV_CTL_ELEM_TYPE_BOOLEAN] = 128, | ||
| 1196 | [SNDRV_CTL_ELEM_TYPE_INTEGER] = 128, | ||
| 1197 | [SNDRV_CTL_ELEM_TYPE_ENUMERATED] = 128, | ||
| 1198 | [SNDRV_CTL_ELEM_TYPE_BYTES] = 512, | ||
| 1199 | [SNDRV_CTL_ELEM_TYPE_IEC958] = 1, | ||
| 1200 | [SNDRV_CTL_ELEM_TYPE_INTEGER64] = 64, | ||
| 1201 | }; | ||
| 1164 | struct snd_card *card = file->card; | 1202 | struct snd_card *card = file->card; |
| 1165 | struct snd_kcontrol kctl, *_kctl; | 1203 | struct snd_kcontrol *kctl; |
| 1204 | unsigned int count; | ||
| 1166 | unsigned int access; | 1205 | unsigned int access; |
| 1167 | long private_size; | 1206 | long private_size; |
| 1168 | struct user_element *ue; | 1207 | struct user_element *ue; |
| 1169 | int idx, err; | 1208 | int err; |
| 1170 | 1209 | ||
| 1171 | if (info->count < 1) | ||
| 1172 | return -EINVAL; | ||
| 1173 | if (!*info->id.name) | 1210 | if (!*info->id.name) |
| 1174 | return -EINVAL; | 1211 | return -EINVAL; |
| 1175 | if (strnlen(info->id.name, sizeof(info->id.name)) >= sizeof(info->id.name)) | 1212 | if (strnlen(info->id.name, sizeof(info->id.name)) >= sizeof(info->id.name)) |
| 1176 | return -EINVAL; | 1213 | return -EINVAL; |
| 1177 | access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : | ||
| 1178 | (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| | ||
| 1179 | SNDRV_CTL_ELEM_ACCESS_INACTIVE| | ||
| 1180 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)); | ||
| 1181 | info->id.numid = 0; | ||
| 1182 | memset(&kctl, 0, sizeof(kctl)); | ||
| 1183 | 1214 | ||
| 1215 | /* Delete a control to replace them if needed. */ | ||
| 1184 | if (replace) { | 1216 | if (replace) { |
| 1217 | info->id.numid = 0; | ||
| 1185 | err = snd_ctl_remove_user_ctl(file, &info->id); | 1218 | err = snd_ctl_remove_user_ctl(file, &info->id); |
| 1186 | if (err) | 1219 | if (err) |
| 1187 | return err; | 1220 | return err; |
| 1188 | } | 1221 | } |
| 1189 | 1222 | ||
| 1190 | if (card->user_ctl_count >= MAX_USER_CONTROLS) | 1223 | /* |
| 1224 | * The number of userspace controls are counted control by control, | ||
| 1225 | * not element by element. | ||
| 1226 | */ | ||
| 1227 | if (card->user_ctl_count + 1 > MAX_USER_CONTROLS) | ||
| 1191 | return -ENOMEM; | 1228 | return -ENOMEM; |
| 1192 | 1229 | ||
| 1193 | memcpy(&kctl.id, &info->id, sizeof(info->id)); | 1230 | /* Check the number of elements for this userspace control. */ |
| 1194 | kctl.count = info->owner ? info->owner : 1; | 1231 | count = info->owner; |
| 1195 | access |= SNDRV_CTL_ELEM_ACCESS_USER; | 1232 | if (count == 0) |
| 1196 | if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) | 1233 | count = 1; |
| 1197 | kctl.info = snd_ctl_elem_user_enum_info; | 1234 | |
| 1198 | else | 1235 | /* Arrange access permissions if needed. */ |
| 1199 | kctl.info = snd_ctl_elem_user_info; | 1236 | access = info->access; |
| 1200 | if (access & SNDRV_CTL_ELEM_ACCESS_READ) | 1237 | if (access == 0) |
| 1201 | kctl.get = snd_ctl_elem_user_get; | 1238 | access = SNDRV_CTL_ELEM_ACCESS_READWRITE; |
| 1202 | if (access & SNDRV_CTL_ELEM_ACCESS_WRITE) | 1239 | access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| 1203 | kctl.put = snd_ctl_elem_user_put; | 1240 | SNDRV_CTL_ELEM_ACCESS_INACTIVE | |
| 1204 | if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) { | 1241 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE); |
| 1205 | kctl.tlv.c = snd_ctl_elem_user_tlv; | 1242 | if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) |
| 1206 | access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; | 1243 | access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; |
| 1207 | } | 1244 | access |= SNDRV_CTL_ELEM_ACCESS_USER; |
| 1208 | switch (info->type) { | 1245 | |
| 1209 | case SNDRV_CTL_ELEM_TYPE_BOOLEAN: | 1246 | /* |
| 1210 | case SNDRV_CTL_ELEM_TYPE_INTEGER: | 1247 | * Check information and calculate the size of data specific to |
| 1211 | private_size = sizeof(long); | 1248 | * this userspace control. |
| 1212 | if (info->count > 128) | 1249 | */ |
| 1213 | return -EINVAL; | 1250 | if (info->type < SNDRV_CTL_ELEM_TYPE_BOOLEAN || |
| 1214 | break; | 1251 | info->type > SNDRV_CTL_ELEM_TYPE_INTEGER64) |
| 1215 | case SNDRV_CTL_ELEM_TYPE_INTEGER64: | ||
| 1216 | private_size = sizeof(long long); | ||
| 1217 | if (info->count > 64) | ||
| 1218 | return -EINVAL; | ||
| 1219 | break; | ||
| 1220 | case SNDRV_CTL_ELEM_TYPE_ENUMERATED: | ||
| 1221 | private_size = sizeof(unsigned int); | ||
| 1222 | if (info->count > 128 || info->value.enumerated.items == 0) | ||
| 1223 | return -EINVAL; | ||
| 1224 | break; | ||
| 1225 | case SNDRV_CTL_ELEM_TYPE_BYTES: | ||
| 1226 | private_size = sizeof(unsigned char); | ||
| 1227 | if (info->count > 512) | ||
| 1228 | return -EINVAL; | ||
| 1229 | break; | ||
| 1230 | case SNDRV_CTL_ELEM_TYPE_IEC958: | ||
| 1231 | private_size = sizeof(struct snd_aes_iec958); | ||
| 1232 | if (info->count != 1) | ||
| 1233 | return -EINVAL; | ||
| 1234 | break; | ||
| 1235 | default: | ||
| 1236 | return -EINVAL; | 1252 | return -EINVAL; |
| 1237 | } | 1253 | if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED && |
| 1238 | private_size *= info->count; | 1254 | info->value.enumerated.items == 0) |
| 1239 | ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL); | 1255 | return -EINVAL; |
| 1240 | if (ue == NULL) | 1256 | if (info->count < 1 || |
| 1257 | info->count > max_value_counts[info->type]) | ||
| 1258 | return -EINVAL; | ||
| 1259 | private_size = value_sizes[info->type] * info->count; | ||
| 1260 | |||
| 1261 | /* | ||
| 1262 | * Keep memory object for this userspace control. After passing this | ||
| 1263 | * code block, the instance should be freed by snd_ctl_free_one(). | ||
| 1264 | * | ||
| 1265 | * Note that these elements in this control are locked. | ||
| 1266 | */ | ||
| 1267 | err = snd_ctl_new(&kctl, count, access, file); | ||
| 1268 | if (err < 0) | ||
| 1269 | return err; | ||
| 1270 | memcpy(&kctl->id, &info->id, sizeof(kctl->id)); | ||
| 1271 | kctl->private_data = kzalloc(sizeof(struct user_element) + private_size, | ||
| 1272 | GFP_KERNEL); | ||
| 1273 | if (kctl->private_data == NULL) { | ||
| 1274 | kfree(kctl); | ||
| 1241 | return -ENOMEM; | 1275 | return -ENOMEM; |
| 1276 | } | ||
| 1277 | kctl->private_free = snd_ctl_elem_user_free; | ||
| 1278 | |||
| 1279 | /* Set private data for this userspace control. */ | ||
| 1280 | ue = (struct user_element *)kctl->private_data; | ||
| 1242 | ue->card = card; | 1281 | ue->card = card; |
| 1243 | ue->info = *info; | 1282 | ue->info = *info; |
| 1244 | ue->info.access = 0; | 1283 | ue->info.access = 0; |
| @@ -1247,21 +1286,25 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, | |||
| 1247 | if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { | 1286 | if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { |
| 1248 | err = snd_ctl_elem_init_enum_names(ue); | 1287 | err = snd_ctl_elem_init_enum_names(ue); |
| 1249 | if (err < 0) { | 1288 | if (err < 0) { |
| 1250 | kfree(ue); | 1289 | snd_ctl_free_one(kctl); |
| 1251 | return err; | 1290 | return err; |
| 1252 | } | 1291 | } |
| 1253 | } | 1292 | } |
| 1254 | kctl.private_free = snd_ctl_elem_user_free; | 1293 | |
| 1255 | _kctl = snd_ctl_new(&kctl, access); | 1294 | /* Set callback functions. */ |
| 1256 | if (_kctl == NULL) { | 1295 | if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) |
| 1257 | kfree(ue->priv_data); | 1296 | kctl->info = snd_ctl_elem_user_enum_info; |
| 1258 | kfree(ue); | 1297 | else |
| 1259 | return -ENOMEM; | 1298 | kctl->info = snd_ctl_elem_user_info; |
| 1260 | } | 1299 | if (access & SNDRV_CTL_ELEM_ACCESS_READ) |
| 1261 | _kctl->private_data = ue; | 1300 | kctl->get = snd_ctl_elem_user_get; |
| 1262 | for (idx = 0; idx < _kctl->count; idx++) | 1301 | if (access & SNDRV_CTL_ELEM_ACCESS_WRITE) |
| 1263 | _kctl->vd[idx].owner = file; | 1302 | kctl->put = snd_ctl_elem_user_put; |
| 1264 | err = snd_ctl_add(card, _kctl); | 1303 | if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) |
| 1304 | kctl->tlv.c = snd_ctl_elem_user_tlv; | ||
| 1305 | |||
| 1306 | /* This function manage to free the instance on failure. */ | ||
| 1307 | err = snd_ctl_add(card, kctl); | ||
| 1265 | if (err < 0) | 1308 | if (err < 0) |
| 1266 | return err; | 1309 | return err; |
| 1267 | 1310 | ||
diff --git a/sound/core/device.c b/sound/core/device.c index 41bec3075ae5..8918838b1999 100644 --- a/sound/core/device.c +++ b/sound/core/device.c | |||
| @@ -50,10 +50,8 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type, | |||
| 50 | if (snd_BUG_ON(!card || !device_data || !ops)) | 50 | if (snd_BUG_ON(!card || !device_data || !ops)) |
| 51 | return -ENXIO; | 51 | return -ENXIO; |
| 52 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 52 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
| 53 | if (dev == NULL) { | 53 | if (!dev) |
| 54 | dev_err(card->dev, "Cannot allocate device, type=%d\n", type); | ||
| 55 | return -ENOMEM; | 54 | return -ENOMEM; |
| 56 | } | ||
| 57 | INIT_LIST_HEAD(&dev->list); | 55 | INIT_LIST_HEAD(&dev->list); |
| 58 | dev->card = card; | 56 | dev->card = card; |
| 59 | dev->type = type; | 57 | dev->type = type; |
| @@ -73,7 +71,7 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type, | |||
| 73 | } | 71 | } |
| 74 | EXPORT_SYMBOL(snd_device_new); | 72 | EXPORT_SYMBOL(snd_device_new); |
| 75 | 73 | ||
| 76 | static int __snd_device_disconnect(struct snd_device *dev) | 74 | static void __snd_device_disconnect(struct snd_device *dev) |
| 77 | { | 75 | { |
| 78 | if (dev->state == SNDRV_DEV_REGISTERED) { | 76 | if (dev->state == SNDRV_DEV_REGISTERED) { |
| 79 | if (dev->ops->dev_disconnect && | 77 | if (dev->ops->dev_disconnect && |
| @@ -81,7 +79,6 @@ static int __snd_device_disconnect(struct snd_device *dev) | |||
| 81 | dev_err(dev->card->dev, "device disconnect failure\n"); | 79 | dev_err(dev->card->dev, "device disconnect failure\n"); |
| 82 | dev->state = SNDRV_DEV_DISCONNECTED; | 80 | dev->state = SNDRV_DEV_DISCONNECTED; |
| 83 | } | 81 | } |
| 84 | return 0; | ||
| 85 | } | 82 | } |
| 86 | 83 | ||
| 87 | static void __snd_device_free(struct snd_device *dev) | 84 | static void __snd_device_free(struct snd_device *dev) |
| @@ -109,6 +106,34 @@ static struct snd_device *look_for_dev(struct snd_card *card, void *device_data) | |||
| 109 | } | 106 | } |
| 110 | 107 | ||
| 111 | /** | 108 | /** |
| 109 | * snd_device_disconnect - disconnect the device | ||
| 110 | * @card: the card instance | ||
| 111 | * @device_data: the data pointer to disconnect | ||
| 112 | * | ||
| 113 | * Turns the device into the disconnection state, invoking | ||
| 114 | * dev_disconnect callback, if the device was already registered. | ||
| 115 | * | ||
| 116 | * Usually called from snd_card_disconnect(). | ||
| 117 | * | ||
| 118 | * Return: Zero if successful, or a negative error code on failure or if the | ||
| 119 | * device not found. | ||
| 120 | */ | ||
| 121 | void snd_device_disconnect(struct snd_card *card, void *device_data) | ||
| 122 | { | ||
| 123 | struct snd_device *dev; | ||
| 124 | |||
| 125 | if (snd_BUG_ON(!card || !device_data)) | ||
| 126 | return; | ||
| 127 | dev = look_for_dev(card, device_data); | ||
| 128 | if (dev) | ||
| 129 | __snd_device_disconnect(dev); | ||
| 130 | else | ||
| 131 | dev_dbg(card->dev, "device disconnect %p (from %pF), not found\n", | ||
| 132 | device_data, __builtin_return_address(0)); | ||
| 133 | } | ||
| 134 | EXPORT_SYMBOL_GPL(snd_device_disconnect); | ||
| 135 | |||
| 136 | /** | ||
| 112 | * snd_device_free - release the device from the card | 137 | * snd_device_free - release the device from the card |
| 113 | * @card: the card instance | 138 | * @card: the card instance |
| 114 | * @device_data: the data pointer to release | 139 | * @device_data: the data pointer to release |
| @@ -195,18 +220,14 @@ int snd_device_register_all(struct snd_card *card) | |||
| 195 | * disconnect all the devices on the card. | 220 | * disconnect all the devices on the card. |
| 196 | * called from init.c | 221 | * called from init.c |
| 197 | */ | 222 | */ |
| 198 | int snd_device_disconnect_all(struct snd_card *card) | 223 | void snd_device_disconnect_all(struct snd_card *card) |
| 199 | { | 224 | { |
| 200 | struct snd_device *dev; | 225 | struct snd_device *dev; |
| 201 | int err = 0; | ||
| 202 | 226 | ||
| 203 | if (snd_BUG_ON(!card)) | 227 | if (snd_BUG_ON(!card)) |
| 204 | return -ENXIO; | 228 | return; |
| 205 | list_for_each_entry_reverse(dev, &card->devices, list) { | 229 | list_for_each_entry_reverse(dev, &card->devices, list) |
| 206 | if (__snd_device_disconnect(dev) < 0) | 230 | __snd_device_disconnect(dev); |
| 207 | err = -ENXIO; | ||
| 208 | } | ||
| 209 | return err; | ||
| 210 | } | 231 | } |
| 211 | 232 | ||
| 212 | /* | 233 | /* |
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 84244a5143cf..51692c8a39ea 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c | |||
| @@ -378,10 +378,8 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device, | |||
| 378 | if (rhwdep) | 378 | if (rhwdep) |
| 379 | *rhwdep = NULL; | 379 | *rhwdep = NULL; |
| 380 | hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL); | 380 | hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL); |
| 381 | if (hwdep == NULL) { | 381 | if (!hwdep) |
| 382 | dev_err(card->dev, "hwdep: cannot allocate\n"); | ||
| 383 | return -ENOMEM; | 382 | return -ENOMEM; |
| 384 | } | ||
| 385 | 383 | ||
| 386 | init_waitqueue_head(&hwdep->open_wait); | 384 | init_waitqueue_head(&hwdep->open_wait); |
| 387 | mutex_init(&hwdep->open_mutex); | 385 | mutex_init(&hwdep->open_mutex); |
diff --git a/sound/core/init.c b/sound/core/init.c index 35419054821c..04734e047bfe 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
| @@ -400,7 +400,6 @@ static const struct file_operations snd_shutdown_f_ops = | |||
| 400 | int snd_card_disconnect(struct snd_card *card) | 400 | int snd_card_disconnect(struct snd_card *card) |
| 401 | { | 401 | { |
| 402 | struct snd_monitor_file *mfile; | 402 | struct snd_monitor_file *mfile; |
| 403 | int err; | ||
| 404 | 403 | ||
| 405 | if (!card) | 404 | if (!card) |
| 406 | return -EINVAL; | 405 | return -EINVAL; |
| @@ -445,9 +444,7 @@ int snd_card_disconnect(struct snd_card *card) | |||
| 445 | #endif | 444 | #endif |
| 446 | 445 | ||
| 447 | /* notify all devices that we are disconnected */ | 446 | /* notify all devices that we are disconnected */ |
| 448 | err = snd_device_disconnect_all(card); | 447 | snd_device_disconnect_all(card); |
| 449 | if (err < 0) | ||
| 450 | dev_err(card->dev, "not all devices for card %i can be disconnected\n", card->number); | ||
| 451 | 448 | ||
| 452 | snd_info_card_disconnect(card); | 449 | snd_info_card_disconnect(card); |
| 453 | if (card->registered) { | 450 | if (card->registered) { |
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 5e6349f00ecd..056f8e274851 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c | |||
| @@ -1212,10 +1212,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry, | |||
| 1212 | /* not changed */ | 1212 | /* not changed */ |
| 1213 | goto __unlock; | 1213 | goto __unlock; |
| 1214 | tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); | 1214 | tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); |
| 1215 | if (! tbl) { | 1215 | if (!tbl) |
| 1216 | pr_err("ALSA: mixer_oss: no memory\n"); | ||
| 1217 | goto __unlock; | 1216 | goto __unlock; |
| 1218 | } | ||
| 1219 | tbl->oss_id = ch; | 1217 | tbl->oss_id = ch; |
| 1220 | tbl->name = kstrdup(str, GFP_KERNEL); | 1218 | tbl->name = kstrdup(str, GFP_KERNEL); |
| 1221 | if (! tbl->name) { | 1219 | if (! tbl->name) { |
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 80423a4ccab6..58550cc93f28 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
| @@ -854,7 +854,6 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) | |||
| 854 | params = kmalloc(sizeof(*params), GFP_KERNEL); | 854 | params = kmalloc(sizeof(*params), GFP_KERNEL); |
| 855 | sparams = kmalloc(sizeof(*sparams), GFP_KERNEL); | 855 | sparams = kmalloc(sizeof(*sparams), GFP_KERNEL); |
| 856 | if (!sw_params || !params || !sparams) { | 856 | if (!sw_params || !params || !sparams) { |
| 857 | pcm_dbg(substream->pcm, "No memory\n"); | ||
| 858 | err = -ENOMEM; | 857 | err = -ENOMEM; |
| 859 | goto failure; | 858 | goto failure; |
| 860 | } | 859 | } |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 0345e53a340c..b25bcf5b8644 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
| @@ -49,8 +49,6 @@ static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device) | |||
| 49 | struct snd_pcm *pcm; | 49 | struct snd_pcm *pcm; |
| 50 | 50 | ||
| 51 | list_for_each_entry(pcm, &snd_pcm_devices, list) { | 51 | list_for_each_entry(pcm, &snd_pcm_devices, list) { |
| 52 | if (pcm->internal) | ||
| 53 | continue; | ||
| 54 | if (pcm->card == card && pcm->device == device) | 52 | if (pcm->card == card && pcm->device == device) |
| 55 | return pcm; | 53 | return pcm; |
| 56 | } | 54 | } |
| @@ -62,8 +60,6 @@ static int snd_pcm_next(struct snd_card *card, int device) | |||
| 62 | struct snd_pcm *pcm; | 60 | struct snd_pcm *pcm; |
| 63 | 61 | ||
| 64 | list_for_each_entry(pcm, &snd_pcm_devices, list) { | 62 | list_for_each_entry(pcm, &snd_pcm_devices, list) { |
| 65 | if (pcm->internal) | ||
| 66 | continue; | ||
| 67 | if (pcm->card == card && pcm->device > device) | 63 | if (pcm->card == card && pcm->device > device) |
| 68 | return pcm->device; | 64 | return pcm->device; |
| 69 | else if (pcm->card->number > card->number) | 65 | else if (pcm->card->number > card->number) |
| @@ -76,6 +72,9 @@ static int snd_pcm_add(struct snd_pcm *newpcm) | |||
| 76 | { | 72 | { |
| 77 | struct snd_pcm *pcm; | 73 | struct snd_pcm *pcm; |
| 78 | 74 | ||
| 75 | if (newpcm->internal) | ||
| 76 | return 0; | ||
| 77 | |||
| 79 | list_for_each_entry(pcm, &snd_pcm_devices, list) { | 78 | list_for_each_entry(pcm, &snd_pcm_devices, list) { |
| 80 | if (pcm->card == newpcm->card && pcm->device == newpcm->device) | 79 | if (pcm->card == newpcm->card && pcm->device == newpcm->device) |
| 81 | return -EBUSY; | 80 | return -EBUSY; |
| @@ -344,11 +343,8 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream, | |||
| 344 | return; | 343 | return; |
| 345 | 344 | ||
| 346 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 345 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
| 347 | if (! info) { | 346 | if (!info) |
| 348 | pcm_dbg(substream->pcm, | ||
| 349 | "snd_pcm_proc_info_read: cannot malloc\n"); | ||
| 350 | return; | 347 | return; |
| 351 | } | ||
| 352 | 348 | ||
| 353 | err = snd_pcm_info(substream, info); | 349 | err = snd_pcm_info(substream, info); |
| 354 | if (err < 0) { | 350 | if (err < 0) { |
| @@ -718,10 +714,8 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) | |||
| 718 | prev = NULL; | 714 | prev = NULL; |
| 719 | for (idx = 0, prev = NULL; idx < substream_count; idx++) { | 715 | for (idx = 0, prev = NULL; idx < substream_count; idx++) { |
| 720 | substream = kzalloc(sizeof(*substream), GFP_KERNEL); | 716 | substream = kzalloc(sizeof(*substream), GFP_KERNEL); |
| 721 | if (substream == NULL) { | 717 | if (!substream) |
| 722 | pcm_err(pcm, "Cannot allocate PCM substream\n"); | ||
| 723 | return -ENOMEM; | 718 | return -ENOMEM; |
| 724 | } | ||
| 725 | substream->pcm = pcm; | 719 | substream->pcm = pcm; |
| 726 | substream->pstr = pstr; | 720 | substream->pstr = pstr; |
| 727 | substream->number = idx; | 721 | substream->number = idx; |
| @@ -775,13 +769,14 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device, | |||
| 775 | if (rpcm) | 769 | if (rpcm) |
| 776 | *rpcm = NULL; | 770 | *rpcm = NULL; |
| 777 | pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); | 771 | pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); |
| 778 | if (pcm == NULL) { | 772 | if (!pcm) |
| 779 | dev_err(card->dev, "Cannot allocate PCM\n"); | ||
| 780 | return -ENOMEM; | 773 | return -ENOMEM; |
| 781 | } | ||
| 782 | pcm->card = card; | 774 | pcm->card = card; |
| 783 | pcm->device = device; | 775 | pcm->device = device; |
| 784 | pcm->internal = internal; | 776 | pcm->internal = internal; |
| 777 | mutex_init(&pcm->open_mutex); | ||
| 778 | init_waitqueue_head(&pcm->open_wait); | ||
| 779 | INIT_LIST_HEAD(&pcm->list); | ||
| 785 | if (id) | 780 | if (id) |
| 786 | strlcpy(pcm->id, id, sizeof(pcm->id)); | 781 | strlcpy(pcm->id, id, sizeof(pcm->id)); |
| 787 | if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) { | 782 | if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) { |
| @@ -792,8 +787,6 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device, | |||
| 792 | snd_pcm_free(pcm); | 787 | snd_pcm_free(pcm); |
| 793 | return err; | 788 | return err; |
| 794 | } | 789 | } |
| 795 | mutex_init(&pcm->open_mutex); | ||
| 796 | init_waitqueue_head(&pcm->open_wait); | ||
| 797 | if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) { | 790 | if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) { |
| 798 | snd_pcm_free(pcm); | 791 | snd_pcm_free(pcm); |
| 799 | return err; | 792 | return err; |
| @@ -888,8 +881,9 @@ static int snd_pcm_free(struct snd_pcm *pcm) | |||
| 888 | 881 | ||
| 889 | if (!pcm) | 882 | if (!pcm) |
| 890 | return 0; | 883 | return 0; |
| 891 | list_for_each_entry(notify, &snd_pcm_notify_list, list) { | 884 | if (!pcm->internal) { |
| 892 | notify->n_unregister(pcm); | 885 | list_for_each_entry(notify, &snd_pcm_notify_list, list) |
| 886 | notify->n_unregister(pcm); | ||
| 893 | } | 887 | } |
| 894 | if (pcm->private_free) | 888 | if (pcm->private_free) |
| 895 | pcm->private_free(pcm); | 889 | pcm->private_free(pcm); |
| @@ -919,6 +913,9 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
| 919 | 913 | ||
| 920 | if (snd_BUG_ON(!pcm || !rsubstream)) | 914 | if (snd_BUG_ON(!pcm || !rsubstream)) |
| 921 | return -ENXIO; | 915 | return -ENXIO; |
| 916 | if (snd_BUG_ON(stream != SNDRV_PCM_STREAM_PLAYBACK && | ||
| 917 | stream != SNDRV_PCM_STREAM_CAPTURE)) | ||
| 918 | return -EINVAL; | ||
| 922 | *rsubstream = NULL; | 919 | *rsubstream = NULL; |
| 923 | pstr = &pcm->streams[stream]; | 920 | pstr = &pcm->streams[stream]; |
| 924 | if (pstr->substream == NULL || pstr->substream_count == 0) | 921 | if (pstr->substream == NULL || pstr->substream_count == 0) |
| @@ -927,25 +924,14 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
| 927 | card = pcm->card; | 924 | card = pcm->card; |
| 928 | prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM); | 925 | prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM); |
| 929 | 926 | ||
| 930 | switch (stream) { | 927 | if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { |
| 931 | case SNDRV_PCM_STREAM_PLAYBACK: | 928 | int opposite = !stream; |
| 932 | if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { | 929 | |
| 933 | for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) { | 930 | for (substream = pcm->streams[opposite].substream; substream; |
| 934 | if (SUBSTREAM_BUSY(substream)) | 931 | substream = substream->next) { |
| 935 | return -EAGAIN; | 932 | if (SUBSTREAM_BUSY(substream)) |
| 936 | } | 933 | return -EAGAIN; |
| 937 | } | ||
| 938 | break; | ||
| 939 | case SNDRV_PCM_STREAM_CAPTURE: | ||
| 940 | if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { | ||
| 941 | for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) { | ||
| 942 | if (SUBSTREAM_BUSY(substream)) | ||
| 943 | return -EAGAIN; | ||
| 944 | } | ||
| 945 | } | 934 | } |
| 946 | break; | ||
| 947 | default: | ||
| 948 | return -EINVAL; | ||
| 949 | } | 935 | } |
| 950 | 936 | ||
| 951 | if (file->f_flags & O_APPEND) { | 937 | if (file->f_flags & O_APPEND) { |
| @@ -968,15 +954,12 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
| 968 | return 0; | 954 | return 0; |
| 969 | } | 955 | } |
| 970 | 956 | ||
| 971 | if (prefer_subdevice >= 0) { | 957 | for (substream = pstr->substream; substream; substream = substream->next) { |
| 972 | for (substream = pstr->substream; substream; substream = substream->next) | 958 | if (!SUBSTREAM_BUSY(substream) && |
| 973 | if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice) | 959 | (prefer_subdevice == -1 || |
| 974 | goto __ok; | 960 | substream->number == prefer_subdevice)) |
| 975 | } | ||
| 976 | for (substream = pstr->substream; substream; substream = substream->next) | ||
| 977 | if (!SUBSTREAM_BUSY(substream)) | ||
| 978 | break; | 961 | break; |
| 979 | __ok: | 962 | } |
| 980 | if (substream == NULL) | 963 | if (substream == NULL) |
| 981 | return -EAGAIN; | 964 | return -EAGAIN; |
| 982 | 965 | ||
| @@ -1086,15 +1069,16 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
| 1086 | if (snd_BUG_ON(!device || !device->device_data)) | 1069 | if (snd_BUG_ON(!device || !device->device_data)) |
| 1087 | return -ENXIO; | 1070 | return -ENXIO; |
| 1088 | pcm = device->device_data; | 1071 | pcm = device->device_data; |
| 1072 | if (pcm->internal) | ||
| 1073 | return 0; | ||
| 1074 | |||
| 1089 | mutex_lock(®ister_mutex); | 1075 | mutex_lock(®ister_mutex); |
| 1090 | err = snd_pcm_add(pcm); | 1076 | err = snd_pcm_add(pcm); |
| 1091 | if (err) { | 1077 | if (err) |
| 1092 | mutex_unlock(®ister_mutex); | 1078 | goto unlock; |
| 1093 | return err; | ||
| 1094 | } | ||
| 1095 | for (cidx = 0; cidx < 2; cidx++) { | 1079 | for (cidx = 0; cidx < 2; cidx++) { |
| 1096 | int devtype = -1; | 1080 | int devtype = -1; |
| 1097 | if (pcm->streams[cidx].substream == NULL || pcm->internal) | 1081 | if (pcm->streams[cidx].substream == NULL) |
| 1098 | continue; | 1082 | continue; |
| 1099 | switch (cidx) { | 1083 | switch (cidx) { |
| 1100 | case SNDRV_PCM_STREAM_PLAYBACK: | 1084 | case SNDRV_PCM_STREAM_PLAYBACK: |
| @@ -1109,9 +1093,8 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
| 1109 | &snd_pcm_f_ops[cidx], pcm, | 1093 | &snd_pcm_f_ops[cidx], pcm, |
| 1110 | &pcm->streams[cidx].dev); | 1094 | &pcm->streams[cidx].dev); |
| 1111 | if (err < 0) { | 1095 | if (err < 0) { |
| 1112 | list_del(&pcm->list); | 1096 | list_del_init(&pcm->list); |
| 1113 | mutex_unlock(®ister_mutex); | 1097 | goto unlock; |
| 1114 | return err; | ||
| 1115 | } | 1098 | } |
| 1116 | 1099 | ||
| 1117 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) | 1100 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) |
| @@ -1121,8 +1104,9 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
| 1121 | list_for_each_entry(notify, &snd_pcm_notify_list, list) | 1104 | list_for_each_entry(notify, &snd_pcm_notify_list, list) |
| 1122 | notify->n_register(pcm); | 1105 | notify->n_register(pcm); |
| 1123 | 1106 | ||
| 1107 | unlock: | ||
| 1124 | mutex_unlock(®ister_mutex); | 1108 | mutex_unlock(®ister_mutex); |
| 1125 | return 0; | 1109 | return err; |
| 1126 | } | 1110 | } |
| 1127 | 1111 | ||
| 1128 | static int snd_pcm_dev_disconnect(struct snd_device *device) | 1112 | static int snd_pcm_dev_disconnect(struct snd_device *device) |
| @@ -1133,13 +1117,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) | |||
| 1133 | int cidx; | 1117 | int cidx; |
| 1134 | 1118 | ||
| 1135 | mutex_lock(®ister_mutex); | 1119 | mutex_lock(®ister_mutex); |
| 1136 | if (list_empty(&pcm->list)) | ||
| 1137 | goto unlock; | ||
| 1138 | |||
| 1139 | mutex_lock(&pcm->open_mutex); | 1120 | mutex_lock(&pcm->open_mutex); |
| 1140 | wake_up(&pcm->open_wait); | 1121 | wake_up(&pcm->open_wait); |
| 1141 | list_del_init(&pcm->list); | 1122 | list_del_init(&pcm->list); |
| 1142 | for (cidx = 0; cidx < 2; cidx++) | 1123 | for (cidx = 0; cidx < 2; cidx++) { |
| 1143 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { | 1124 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { |
| 1144 | snd_pcm_stream_lock_irq(substream); | 1125 | snd_pcm_stream_lock_irq(substream); |
| 1145 | if (substream->runtime) { | 1126 | if (substream->runtime) { |
| @@ -1149,18 +1130,20 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) | |||
| 1149 | } | 1130 | } |
| 1150 | snd_pcm_stream_unlock_irq(substream); | 1131 | snd_pcm_stream_unlock_irq(substream); |
| 1151 | } | 1132 | } |
| 1152 | list_for_each_entry(notify, &snd_pcm_notify_list, list) { | 1133 | } |
| 1153 | notify->n_disconnect(pcm); | 1134 | if (!pcm->internal) { |
| 1135 | list_for_each_entry(notify, &snd_pcm_notify_list, list) | ||
| 1136 | notify->n_disconnect(pcm); | ||
| 1154 | } | 1137 | } |
| 1155 | for (cidx = 0; cidx < 2; cidx++) { | 1138 | for (cidx = 0; cidx < 2; cidx++) { |
| 1156 | snd_unregister_device(&pcm->streams[cidx].dev); | 1139 | if (!pcm->internal) |
| 1140 | snd_unregister_device(&pcm->streams[cidx].dev); | ||
| 1157 | if (pcm->streams[cidx].chmap_kctl) { | 1141 | if (pcm->streams[cidx].chmap_kctl) { |
| 1158 | snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl); | 1142 | snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl); |
| 1159 | pcm->streams[cidx].chmap_kctl = NULL; | 1143 | pcm->streams[cidx].chmap_kctl = NULL; |
| 1160 | } | 1144 | } |
| 1161 | } | 1145 | } |
| 1162 | mutex_unlock(&pcm->open_mutex); | 1146 | mutex_unlock(&pcm->open_mutex); |
| 1163 | unlock: | ||
| 1164 | mutex_unlock(®ister_mutex); | 1147 | mutex_unlock(®ister_mutex); |
| 1165 | return 0; | 1148 | return 0; |
| 1166 | } | 1149 | } |
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 2d957ba63557..b48b434444ed 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c | |||
| @@ -194,18 +194,30 @@ struct snd_pcm_status32 { | |||
| 194 | u32 avail_max; | 194 | u32 avail_max; |
| 195 | u32 overrange; | 195 | u32 overrange; |
| 196 | s32 suspended_state; | 196 | s32 suspended_state; |
| 197 | u32 reserved_alignment; | 197 | u32 audio_tstamp_data; |
| 198 | struct compat_timespec audio_tstamp; | 198 | struct compat_timespec audio_tstamp; |
| 199 | unsigned char reserved[56-sizeof(struct compat_timespec)]; | 199 | struct compat_timespec driver_tstamp; |
| 200 | u32 audio_tstamp_accuracy; | ||
| 201 | unsigned char reserved[52-2*sizeof(struct compat_timespec)]; | ||
| 200 | } __attribute__((packed)); | 202 | } __attribute__((packed)); |
| 201 | 203 | ||
| 202 | 204 | ||
| 203 | static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream, | 205 | static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream, |
| 204 | struct snd_pcm_status32 __user *src) | 206 | struct snd_pcm_status32 __user *src, |
| 207 | bool ext) | ||
| 205 | { | 208 | { |
| 206 | struct snd_pcm_status status; | 209 | struct snd_pcm_status status; |
| 207 | int err; | 210 | int err; |
| 208 | 211 | ||
| 212 | memset(&status, 0, sizeof(status)); | ||
| 213 | /* | ||
| 214 | * with extension, parameters are read/write, | ||
| 215 | * get audio_tstamp_data from user, | ||
| 216 | * ignore rest of status structure | ||
| 217 | */ | ||
| 218 | if (ext && get_user(status.audio_tstamp_data, | ||
| 219 | (u32 __user *)(&src->audio_tstamp_data))) | ||
| 220 | return -EFAULT; | ||
| 209 | err = snd_pcm_status(substream, &status); | 221 | err = snd_pcm_status(substream, &status); |
| 210 | if (err < 0) | 222 | if (err < 0) |
| 211 | return err; | 223 | return err; |
| @@ -222,7 +234,10 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream, | |||
| 222 | put_user(status.avail_max, &src->avail_max) || | 234 | put_user(status.avail_max, &src->avail_max) || |
| 223 | put_user(status.overrange, &src->overrange) || | 235 | put_user(status.overrange, &src->overrange) || |
| 224 | put_user(status.suspended_state, &src->suspended_state) || | 236 | put_user(status.suspended_state, &src->suspended_state) || |
| 225 | compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp)) | 237 | put_user(status.audio_tstamp_data, &src->audio_tstamp_data) || |
| 238 | compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp) || | ||
| 239 | compat_put_timespec(&status.driver_tstamp, &src->driver_tstamp) || | ||
| 240 | put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy)) | ||
| 226 | return -EFAULT; | 241 | return -EFAULT; |
| 227 | 242 | ||
| 228 | return err; | 243 | return err; |
| @@ -457,6 +472,7 @@ enum { | |||
| 457 | SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32), | 472 | SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32), |
| 458 | SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32), | 473 | SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32), |
| 459 | SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct snd_pcm_status32), | 474 | SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct snd_pcm_status32), |
| 475 | SNDRV_PCM_IOCTL_STATUS_EXT32 = _IOWR('A', 0x24, struct snd_pcm_status32), | ||
| 460 | SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32), | 476 | SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32), |
| 461 | SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32), | 477 | SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32), |
| 462 | SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32), | 478 | SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32), |
| @@ -517,7 +533,9 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l | |||
| 517 | case SNDRV_PCM_IOCTL_SW_PARAMS32: | 533 | case SNDRV_PCM_IOCTL_SW_PARAMS32: |
| 518 | return snd_pcm_ioctl_sw_params_compat(substream, argp); | 534 | return snd_pcm_ioctl_sw_params_compat(substream, argp); |
| 519 | case SNDRV_PCM_IOCTL_STATUS32: | 535 | case SNDRV_PCM_IOCTL_STATUS32: |
| 520 | return snd_pcm_status_user_compat(substream, argp); | 536 | return snd_pcm_status_user_compat(substream, argp, false); |
| 537 | case SNDRV_PCM_IOCTL_STATUS_EXT32: | ||
| 538 | return snd_pcm_status_user_compat(substream, argp, true); | ||
| 521 | case SNDRV_PCM_IOCTL_SYNC_PTR32: | 539 | case SNDRV_PCM_IOCTL_SYNC_PTR32: |
| 522 | return snd_pcm_ioctl_sync_ptr_compat(substream, argp); | 540 | return snd_pcm_ioctl_sync_ptr_compat(substream, argp); |
| 523 | case SNDRV_PCM_IOCTL_CHANNEL_INFO32: | 541 | case SNDRV_PCM_IOCTL_CHANNEL_INFO32: |
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index 6542c4083594..fba365a78390 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c | |||
| @@ -289,7 +289,7 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel); | |||
| 289 | * | 289 | * |
| 290 | * The function should usually be called from the pcm open callback. Note that | 290 | * The function should usually be called from the pcm open callback. Note that |
| 291 | * this function will use private_data field of the substream's runtime. So it | 291 | * this function will use private_data field of the substream's runtime. So it |
| 292 | * is not availabe to your pcm driver implementation. | 292 | * is not available to your pcm driver implementation. |
| 293 | */ | 293 | */ |
| 294 | int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, | 294 | int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, |
| 295 | struct dma_chan *chan) | 295 | struct dma_chan *chan) |
| @@ -328,7 +328,7 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open); | |||
| 328 | * This function will request a DMA channel using the passed filter function and | 328 | * This function will request a DMA channel using the passed filter function and |
| 329 | * data. The function should usually be called from the pcm open callback. Note | 329 | * data. The function should usually be called from the pcm open callback. Note |
| 330 | * that this function will use private_data field of the substream's runtime. So | 330 | * that this function will use private_data field of the substream's runtime. So |
| 331 | * it is not availabe to your pcm driver implementation. | 331 | * it is not available to your pcm driver implementation. |
| 332 | */ | 332 | */ |
| 333 | int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, | 333 | int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, |
| 334 | dma_filter_fn filter_fn, void *filter_data) | 334 | dma_filter_fn filter_fn, void *filter_data) |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index ffd656012ab8..ac6b33f3779c 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
| @@ -232,6 +232,49 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, | |||
| 232 | return 0; | 232 | return 0; |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | static void update_audio_tstamp(struct snd_pcm_substream *substream, | ||
| 236 | struct timespec *curr_tstamp, | ||
| 237 | struct timespec *audio_tstamp) | ||
| 238 | { | ||
| 239 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 240 | u64 audio_frames, audio_nsecs; | ||
| 241 | struct timespec driver_tstamp; | ||
| 242 | |||
| 243 | if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE) | ||
| 244 | return; | ||
| 245 | |||
| 246 | if (!(substream->ops->get_time_info) || | ||
| 247 | (runtime->audio_tstamp_report.actual_type == | ||
| 248 | SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) { | ||
| 249 | |||
| 250 | /* | ||
| 251 | * provide audio timestamp derived from pointer position | ||
| 252 | * add delay only if requested | ||
| 253 | */ | ||
| 254 | |||
| 255 | audio_frames = runtime->hw_ptr_wrap + runtime->status->hw_ptr; | ||
| 256 | |||
| 257 | if (runtime->audio_tstamp_config.report_delay) { | ||
| 258 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 259 | audio_frames -= runtime->delay; | ||
| 260 | else | ||
| 261 | audio_frames += runtime->delay; | ||
| 262 | } | ||
| 263 | audio_nsecs = div_u64(audio_frames * 1000000000LL, | ||
| 264 | runtime->rate); | ||
| 265 | *audio_tstamp = ns_to_timespec(audio_nsecs); | ||
| 266 | } | ||
| 267 | runtime->status->audio_tstamp = *audio_tstamp; | ||
| 268 | runtime->status->tstamp = *curr_tstamp; | ||
| 269 | |||
| 270 | /* | ||
| 271 | * re-take a driver timestamp to let apps detect if the reference tstamp | ||
| 272 | * read by low-level hardware was provided with a delay | ||
| 273 | */ | ||
| 274 | snd_pcm_gettime(substream->runtime, (struct timespec *)&driver_tstamp); | ||
| 275 | runtime->driver_tstamp = driver_tstamp; | ||
| 276 | } | ||
| 277 | |||
| 235 | static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | 278 | static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, |
| 236 | unsigned int in_interrupt) | 279 | unsigned int in_interrupt) |
| 237 | { | 280 | { |
| @@ -256,11 +299,18 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
| 256 | pos = substream->ops->pointer(substream); | 299 | pos = substream->ops->pointer(substream); |
| 257 | curr_jiffies = jiffies; | 300 | curr_jiffies = jiffies; |
| 258 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { | 301 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { |
| 259 | snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); | 302 | if ((substream->ops->get_time_info) && |
| 260 | 303 | (runtime->audio_tstamp_config.type_requested != SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) { | |
| 261 | if ((runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) && | 304 | substream->ops->get_time_info(substream, &curr_tstamp, |
| 262 | (substream->ops->wall_clock)) | 305 | &audio_tstamp, |
| 263 | substream->ops->wall_clock(substream, &audio_tstamp); | 306 | &runtime->audio_tstamp_config, |
| 307 | &runtime->audio_tstamp_report); | ||
| 308 | |||
| 309 | /* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */ | ||
| 310 | if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT) | ||
| 311 | snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); | ||
| 312 | } else | ||
| 313 | snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); | ||
| 264 | } | 314 | } |
| 265 | 315 | ||
| 266 | if (pos == SNDRV_PCM_POS_XRUN) { | 316 | if (pos == SNDRV_PCM_POS_XRUN) { |
| @@ -403,8 +453,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
| 403 | } | 453 | } |
| 404 | 454 | ||
| 405 | no_delta_check: | 455 | no_delta_check: |
| 406 | if (runtime->status->hw_ptr == new_hw_ptr) | 456 | if (runtime->status->hw_ptr == new_hw_ptr) { |
| 457 | update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp); | ||
| 407 | return 0; | 458 | return 0; |
| 459 | } | ||
| 408 | 460 | ||
| 409 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 461 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
| 410 | runtime->silence_size > 0) | 462 | runtime->silence_size > 0) |
| @@ -426,30 +478,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
| 426 | snd_BUG_ON(crossed_boundary != 1); | 478 | snd_BUG_ON(crossed_boundary != 1); |
| 427 | runtime->hw_ptr_wrap += runtime->boundary; | 479 | runtime->hw_ptr_wrap += runtime->boundary; |
| 428 | } | 480 | } |
| 429 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { | ||
| 430 | runtime->status->tstamp = curr_tstamp; | ||
| 431 | 481 | ||
| 432 | if (!(runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)) { | 482 | update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp); |
| 433 | /* | ||
| 434 | * no wall clock available, provide audio timestamp | ||
| 435 | * derived from pointer position+delay | ||
| 436 | */ | ||
| 437 | u64 audio_frames, audio_nsecs; | ||
| 438 | |||
| 439 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 440 | audio_frames = runtime->hw_ptr_wrap | ||
| 441 | + runtime->status->hw_ptr | ||
| 442 | - runtime->delay; | ||
| 443 | else | ||
| 444 | audio_frames = runtime->hw_ptr_wrap | ||
| 445 | + runtime->status->hw_ptr | ||
| 446 | + runtime->delay; | ||
| 447 | audio_nsecs = div_u64(audio_frames * 1000000000LL, | ||
| 448 | runtime->rate); | ||
| 449 | audio_tstamp = ns_to_timespec(audio_nsecs); | ||
| 450 | } | ||
| 451 | runtime->status->audio_tstamp = audio_tstamp; | ||
| 452 | } | ||
| 453 | 483 | ||
| 454 | return snd_pcm_update_state(substream, runtime); | 484 | return snd_pcm_update_state(substream, runtime); |
| 455 | } | 485 | } |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 279e24f61305..abe1e811e660 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
| @@ -707,6 +707,23 @@ int snd_pcm_status(struct snd_pcm_substream *substream, | |||
| 707 | struct snd_pcm_runtime *runtime = substream->runtime; | 707 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 708 | 708 | ||
| 709 | snd_pcm_stream_lock_irq(substream); | 709 | snd_pcm_stream_lock_irq(substream); |
| 710 | |||
| 711 | snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data, | ||
| 712 | &runtime->audio_tstamp_config); | ||
| 713 | |||
| 714 | /* backwards compatible behavior */ | ||
| 715 | if (runtime->audio_tstamp_config.type_requested == | ||
| 716 | SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT) { | ||
| 717 | if (runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) | ||
| 718 | runtime->audio_tstamp_config.type_requested = | ||
| 719 | SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; | ||
| 720 | else | ||
| 721 | runtime->audio_tstamp_config.type_requested = | ||
| 722 | SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; | ||
| 723 | runtime->audio_tstamp_report.valid = 0; | ||
| 724 | } else | ||
| 725 | runtime->audio_tstamp_report.valid = 1; | ||
| 726 | |||
| 710 | status->state = runtime->status->state; | 727 | status->state = runtime->status->state; |
| 711 | status->suspended_state = runtime->status->suspended_state; | 728 | status->suspended_state = runtime->status->suspended_state; |
| 712 | if (status->state == SNDRV_PCM_STATE_OPEN) | 729 | if (status->state == SNDRV_PCM_STATE_OPEN) |
| @@ -716,8 +733,15 @@ int snd_pcm_status(struct snd_pcm_substream *substream, | |||
| 716 | snd_pcm_update_hw_ptr(substream); | 733 | snd_pcm_update_hw_ptr(substream); |
| 717 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { | 734 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { |
| 718 | status->tstamp = runtime->status->tstamp; | 735 | status->tstamp = runtime->status->tstamp; |
| 736 | status->driver_tstamp = runtime->driver_tstamp; | ||
| 719 | status->audio_tstamp = | 737 | status->audio_tstamp = |
| 720 | runtime->status->audio_tstamp; | 738 | runtime->status->audio_tstamp; |
| 739 | if (runtime->audio_tstamp_report.valid == 1) | ||
| 740 | /* backwards compatibility, no report provided in COMPAT mode */ | ||
| 741 | snd_pcm_pack_audio_tstamp_report(&status->audio_tstamp_data, | ||
| 742 | &status->audio_tstamp_accuracy, | ||
| 743 | &runtime->audio_tstamp_report); | ||
| 744 | |||
| 721 | goto _tstamp_end; | 745 | goto _tstamp_end; |
| 722 | } | 746 | } |
| 723 | } else { | 747 | } else { |
| @@ -753,12 +777,21 @@ int snd_pcm_status(struct snd_pcm_substream *substream, | |||
| 753 | } | 777 | } |
| 754 | 778 | ||
| 755 | static int snd_pcm_status_user(struct snd_pcm_substream *substream, | 779 | static int snd_pcm_status_user(struct snd_pcm_substream *substream, |
| 756 | struct snd_pcm_status __user * _status) | 780 | struct snd_pcm_status __user * _status, |
| 781 | bool ext) | ||
| 757 | { | 782 | { |
| 758 | struct snd_pcm_status status; | 783 | struct snd_pcm_status status; |
| 759 | int res; | 784 | int res; |
| 760 | 785 | ||
| 761 | memset(&status, 0, sizeof(status)); | 786 | memset(&status, 0, sizeof(status)); |
| 787 | /* | ||
| 788 | * with extension, parameters are read/write, | ||
| 789 | * get audio_tstamp_data from user, | ||
| 790 | * ignore rest of status structure | ||
| 791 | */ | ||
| 792 | if (ext && get_user(status.audio_tstamp_data, | ||
| 793 | (u32 __user *)(&_status->audio_tstamp_data))) | ||
| 794 | return -EFAULT; | ||
| 762 | res = snd_pcm_status(substream, &status); | 795 | res = snd_pcm_status(substream, &status); |
| 763 | if (res < 0) | 796 | if (res < 0) |
| 764 | return res; | 797 | return res; |
| @@ -2725,7 +2758,9 @@ static int snd_pcm_common_ioctl1(struct file *file, | |||
| 2725 | case SNDRV_PCM_IOCTL_SW_PARAMS: | 2758 | case SNDRV_PCM_IOCTL_SW_PARAMS: |
| 2726 | return snd_pcm_sw_params_user(substream, arg); | 2759 | return snd_pcm_sw_params_user(substream, arg); |
| 2727 | case SNDRV_PCM_IOCTL_STATUS: | 2760 | case SNDRV_PCM_IOCTL_STATUS: |
| 2728 | return snd_pcm_status_user(substream, arg); | 2761 | return snd_pcm_status_user(substream, arg, false); |
| 2762 | case SNDRV_PCM_IOCTL_STATUS_EXT: | ||
| 2763 | return snd_pcm_status_user(substream, arg, true); | ||
| 2729 | case SNDRV_PCM_IOCTL_CHANNEL_INFO: | 2764 | case SNDRV_PCM_IOCTL_CHANNEL_INFO: |
| 2730 | return snd_pcm_channel_info_user(substream, arg); | 2765 | return snd_pcm_channel_info_user(substream, arg); |
| 2731 | case SNDRV_PCM_IOCTL_PREPARE: | 2766 | case SNDRV_PCM_IOCTL_PREPARE: |
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index b5a748596fc4..a7759846fbaa 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c | |||
| @@ -1429,10 +1429,8 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi, | |||
| 1429 | 1429 | ||
| 1430 | for (idx = 0; idx < count; idx++) { | 1430 | for (idx = 0; idx < count; idx++) { |
| 1431 | substream = kzalloc(sizeof(*substream), GFP_KERNEL); | 1431 | substream = kzalloc(sizeof(*substream), GFP_KERNEL); |
| 1432 | if (substream == NULL) { | 1432 | if (!substream) |
| 1433 | rmidi_err(rmidi, "rawmidi: cannot allocate substream\n"); | ||
| 1434 | return -ENOMEM; | 1433 | return -ENOMEM; |
| 1435 | } | ||
| 1436 | substream->stream = direction; | 1434 | substream->stream = direction; |
| 1437 | substream->number = idx; | 1435 | substream->number = idx; |
| 1438 | substream->rmidi = rmidi; | 1436 | substream->rmidi = rmidi; |
| @@ -1479,10 +1477,8 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device, | |||
| 1479 | if (rrawmidi) | 1477 | if (rrawmidi) |
| 1480 | *rrawmidi = NULL; | 1478 | *rrawmidi = NULL; |
| 1481 | rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL); | 1479 | rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL); |
| 1482 | if (rmidi == NULL) { | 1480 | if (!rmidi) |
| 1483 | dev_err(card->dev, "rawmidi: cannot allocate\n"); | ||
| 1484 | return -ENOMEM; | 1481 | return -ENOMEM; |
| 1485 | } | ||
| 1486 | rmidi->card = card; | 1482 | rmidi->card = card; |
| 1487 | rmidi->device = device; | 1483 | rmidi->device = device; |
| 1488 | mutex_init(&rmidi->open_mutex); | 1484 | mutex_init(&rmidi->open_mutex); |
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index 16d42679e43f..72873a46afeb 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c | |||
| @@ -65,15 +65,20 @@ static unsigned int odev_poll(struct file *file, poll_table * wait); | |||
| 65 | * module interface | 65 | * module interface |
| 66 | */ | 66 | */ |
| 67 | 67 | ||
| 68 | static struct snd_seq_driver seq_oss_synth_driver = { | ||
| 69 | .driver = { | ||
| 70 | .name = KBUILD_MODNAME, | ||
| 71 | .probe = snd_seq_oss_synth_probe, | ||
| 72 | .remove = snd_seq_oss_synth_remove, | ||
| 73 | }, | ||
| 74 | .id = SNDRV_SEQ_DEV_ID_OSS, | ||
| 75 | .argsize = sizeof(struct snd_seq_oss_reg), | ||
| 76 | }; | ||
| 77 | |||
| 68 | static int __init alsa_seq_oss_init(void) | 78 | static int __init alsa_seq_oss_init(void) |
| 69 | { | 79 | { |
| 70 | int rc; | 80 | int rc; |
| 71 | static struct snd_seq_dev_ops ops = { | ||
| 72 | snd_seq_oss_synth_register, | ||
| 73 | snd_seq_oss_synth_unregister, | ||
| 74 | }; | ||
| 75 | 81 | ||
| 76 | snd_seq_autoload_lock(); | ||
| 77 | if ((rc = register_device()) < 0) | 82 | if ((rc = register_device()) < 0) |
| 78 | goto error; | 83 | goto error; |
| 79 | if ((rc = register_proc()) < 0) { | 84 | if ((rc = register_proc()) < 0) { |
| @@ -86,8 +91,8 @@ static int __init alsa_seq_oss_init(void) | |||
| 86 | goto error; | 91 | goto error; |
| 87 | } | 92 | } |
| 88 | 93 | ||
| 89 | if ((rc = snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OSS, &ops, | 94 | rc = snd_seq_driver_register(&seq_oss_synth_driver); |
| 90 | sizeof(struct snd_seq_oss_reg))) < 0) { | 95 | if (rc < 0) { |
| 91 | snd_seq_oss_delete_client(); | 96 | snd_seq_oss_delete_client(); |
| 92 | unregister_proc(); | 97 | unregister_proc(); |
| 93 | unregister_device(); | 98 | unregister_device(); |
| @@ -98,13 +103,12 @@ static int __init alsa_seq_oss_init(void) | |||
| 98 | snd_seq_oss_synth_init(); | 103 | snd_seq_oss_synth_init(); |
| 99 | 104 | ||
| 100 | error: | 105 | error: |
| 101 | snd_seq_autoload_unlock(); | ||
| 102 | return rc; | 106 | return rc; |
| 103 | } | 107 | } |
| 104 | 108 | ||
| 105 | static void __exit alsa_seq_oss_exit(void) | 109 | static void __exit alsa_seq_oss_exit(void) |
| 106 | { | 110 | { |
| 107 | snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OSS); | 111 | snd_seq_driver_unregister(&seq_oss_synth_driver); |
| 108 | snd_seq_oss_delete_client(); | 112 | snd_seq_oss_delete_client(); |
| 109 | unregister_proc(); | 113 | unregister_proc(); |
| 110 | unregister_device(); | 114 | unregister_device(); |
diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index b0e32e161dd1..2de3feff70d0 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c | |||
| @@ -188,10 +188,8 @@ snd_seq_oss_open(struct file *file, int level) | |||
| 188 | struct seq_oss_devinfo *dp; | 188 | struct seq_oss_devinfo *dp; |
| 189 | 189 | ||
| 190 | dp = kzalloc(sizeof(*dp), GFP_KERNEL); | 190 | dp = kzalloc(sizeof(*dp), GFP_KERNEL); |
| 191 | if (!dp) { | 191 | if (!dp) |
| 192 | pr_err("ALSA: seq_oss: can't malloc device info\n"); | ||
| 193 | return -ENOMEM; | 192 | return -ENOMEM; |
| 194 | } | ||
| 195 | 193 | ||
| 196 | dp->cseq = system_client; | 194 | dp->cseq = system_client; |
| 197 | dp->port = -1; | 195 | dp->port = -1; |
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index e79cc44b1394..96e8395ae586 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c | |||
| @@ -173,10 +173,9 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo) | |||
| 173 | /* | 173 | /* |
| 174 | * allocate midi info record | 174 | * allocate midi info record |
| 175 | */ | 175 | */ |
| 176 | if ((mdev = kzalloc(sizeof(*mdev), GFP_KERNEL)) == NULL) { | 176 | mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); |
| 177 | pr_err("ALSA: seq_oss: can't malloc midi info\n"); | 177 | if (!mdev) |
| 178 | return -ENOMEM; | 178 | return -ENOMEM; |
| 179 | } | ||
| 180 | 179 | ||
| 181 | /* copy the port information */ | 180 | /* copy the port information */ |
| 182 | mdev->client = pinfo->addr.client; | 181 | mdev->client = pinfo->addr.client; |
diff --git a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c index 654d17a5023c..c080c73cea04 100644 --- a/sound/core/seq/oss/seq_oss_readq.c +++ b/sound/core/seq/oss/seq_oss_readq.c | |||
| @@ -47,13 +47,12 @@ snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen) | |||
| 47 | { | 47 | { |
| 48 | struct seq_oss_readq *q; | 48 | struct seq_oss_readq *q; |
| 49 | 49 | ||
| 50 | if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) { | 50 | q = kzalloc(sizeof(*q), GFP_KERNEL); |
| 51 | pr_err("ALSA: seq_oss: can't malloc read queue\n"); | 51 | if (!q) |
| 52 | return NULL; | 52 | return NULL; |
| 53 | } | ||
| 54 | 53 | ||
| 55 | if ((q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL)) == NULL) { | 54 | q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL); |
| 56 | pr_err("ALSA: seq_oss: can't malloc read queue buffer\n"); | 55 | if (!q->q) { |
| 57 | kfree(q); | 56 | kfree(q); |
| 58 | return NULL; | 57 | return NULL; |
| 59 | } | 58 | } |
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 701feb71b700..48e4fe1b68ab 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c | |||
| @@ -98,17 +98,17 @@ snd_seq_oss_synth_init(void) | |||
| 98 | * registration of the synth device | 98 | * registration of the synth device |
| 99 | */ | 99 | */ |
| 100 | int | 100 | int |
| 101 | snd_seq_oss_synth_register(struct snd_seq_device *dev) | 101 | snd_seq_oss_synth_probe(struct device *_dev) |
| 102 | { | 102 | { |
| 103 | struct snd_seq_device *dev = to_seq_dev(_dev); | ||
| 103 | int i; | 104 | int i; |
| 104 | struct seq_oss_synth *rec; | 105 | struct seq_oss_synth *rec; |
| 105 | struct snd_seq_oss_reg *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev); | 106 | struct snd_seq_oss_reg *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev); |
| 106 | unsigned long flags; | 107 | unsigned long flags; |
| 107 | 108 | ||
| 108 | if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL) { | 109 | rec = kzalloc(sizeof(*rec), GFP_KERNEL); |
| 109 | pr_err("ALSA: seq_oss: can't malloc synth info\n"); | 110 | if (!rec) |
| 110 | return -ENOMEM; | 111 | return -ENOMEM; |
| 111 | } | ||
| 112 | rec->seq_device = -1; | 112 | rec->seq_device = -1; |
| 113 | rec->synth_type = reg->type; | 113 | rec->synth_type = reg->type; |
| 114 | rec->synth_subtype = reg->subtype; | 114 | rec->synth_subtype = reg->subtype; |
| @@ -149,8 +149,9 @@ snd_seq_oss_synth_register(struct snd_seq_device *dev) | |||
| 149 | 149 | ||
| 150 | 150 | ||
| 151 | int | 151 | int |
| 152 | snd_seq_oss_synth_unregister(struct snd_seq_device *dev) | 152 | snd_seq_oss_synth_remove(struct device *_dev) |
| 153 | { | 153 | { |
| 154 | struct snd_seq_device *dev = to_seq_dev(_dev); | ||
| 154 | int index; | 155 | int index; |
| 155 | struct seq_oss_synth *rec = dev->driver_data; | 156 | struct seq_oss_synth *rec = dev->driver_data; |
| 156 | unsigned long flags; | 157 | unsigned long flags; |
| @@ -247,7 +248,6 @@ snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp) | |||
| 247 | if (info->nr_voices > 0) { | 248 | if (info->nr_voices > 0) { |
| 248 | info->ch = kcalloc(info->nr_voices, sizeof(struct seq_oss_chinfo), GFP_KERNEL); | 249 | info->ch = kcalloc(info->nr_voices, sizeof(struct seq_oss_chinfo), GFP_KERNEL); |
| 249 | if (!info->ch) { | 250 | if (!info->ch) { |
| 250 | pr_err("ALSA: seq_oss: Cannot malloc voices\n"); | ||
| 251 | rec->oper.close(&info->arg); | 251 | rec->oper.close(&info->arg); |
| 252 | module_put(rec->oper.owner); | 252 | module_put(rec->oper.owner); |
| 253 | snd_use_lock_free(&rec->use_lock); | 253 | snd_use_lock_free(&rec->use_lock); |
diff --git a/sound/core/seq/oss/seq_oss_synth.h b/sound/core/seq/oss/seq_oss_synth.h index dbdfcbb80eaa..74ac55f166b6 100644 --- a/sound/core/seq/oss/seq_oss_synth.h +++ b/sound/core/seq/oss/seq_oss_synth.h | |||
| @@ -28,8 +28,8 @@ | |||
| 28 | #include <sound/seq_device.h> | 28 | #include <sound/seq_device.h> |
| 29 | 29 | ||
| 30 | void snd_seq_oss_synth_init(void); | 30 | void snd_seq_oss_synth_init(void); |
| 31 | int snd_seq_oss_synth_register(struct snd_seq_device *dev); | 31 | int snd_seq_oss_synth_probe(struct device *dev); |
| 32 | int snd_seq_oss_synth_unregister(struct snd_seq_device *dev); | 32 | int snd_seq_oss_synth_remove(struct device *dev); |
| 33 | void snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp); | 33 | void snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp); |
| 34 | void snd_seq_oss_synth_setup_midi(struct seq_oss_devinfo *dp); | 34 | void snd_seq_oss_synth_setup_midi(struct seq_oss_devinfo *dp); |
| 35 | void snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp); | 35 | void snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp); |
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 0631bdadd12b..d99f99d61983 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | * | 36 | * |
| 37 | */ | 37 | */ |
| 38 | 38 | ||
| 39 | #include <linux/device.h> | ||
| 39 | #include <linux/init.h> | 40 | #include <linux/init.h> |
| 40 | #include <linux/module.h> | 41 | #include <linux/module.h> |
| 41 | #include <sound/core.h> | 42 | #include <sound/core.h> |
| @@ -51,140 +52,78 @@ MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); | |||
| 51 | MODULE_DESCRIPTION("ALSA sequencer device management"); | 52 | MODULE_DESCRIPTION("ALSA sequencer device management"); |
| 52 | MODULE_LICENSE("GPL"); | 53 | MODULE_LICENSE("GPL"); |
| 53 | 54 | ||
| 54 | /* driver state */ | 55 | /* |
| 55 | #define DRIVER_EMPTY 0 | 56 | * bus definition |
| 56 | #define DRIVER_LOADED (1<<0) | 57 | */ |
| 57 | #define DRIVER_REQUESTED (1<<1) | 58 | static int snd_seq_bus_match(struct device *dev, struct device_driver *drv) |
| 58 | #define DRIVER_LOCKED (1<<2) | 59 | { |
| 59 | #define DRIVER_REQUESTING (1<<3) | 60 | struct snd_seq_device *sdev = to_seq_dev(dev); |
| 60 | 61 | struct snd_seq_driver *sdrv = to_seq_drv(drv); | |
| 61 | struct ops_list { | ||
| 62 | char id[ID_LEN]; /* driver id */ | ||
| 63 | int driver; /* driver state */ | ||
| 64 | int used; /* reference counter */ | ||
| 65 | int argsize; /* argument size */ | ||
| 66 | |||
| 67 | /* operators */ | ||
| 68 | struct snd_seq_dev_ops ops; | ||
| 69 | |||
| 70 | /* registered devices */ | ||
| 71 | struct list_head dev_list; /* list of devices */ | ||
| 72 | int num_devices; /* number of associated devices */ | ||
| 73 | int num_init_devices; /* number of initialized devices */ | ||
| 74 | struct mutex reg_mutex; | ||
| 75 | |||
| 76 | struct list_head list; /* next driver */ | ||
| 77 | }; | ||
| 78 | 62 | ||
| 63 | return strcmp(sdrv->id, sdev->id) == 0 && | ||
| 64 | sdrv->argsize == sdev->argsize; | ||
| 65 | } | ||
| 79 | 66 | ||
| 80 | static LIST_HEAD(opslist); | 67 | static struct bus_type snd_seq_bus_type = { |
| 81 | static int num_ops; | 68 | .name = "snd_seq", |
| 82 | static DEFINE_MUTEX(ops_mutex); | 69 | .match = snd_seq_bus_match, |
| 83 | #ifdef CONFIG_PROC_FS | 70 | }; |
| 84 | static struct snd_info_entry *info_entry; | ||
| 85 | #endif | ||
| 86 | 71 | ||
| 87 | /* | 72 | /* |
| 88 | * prototypes | 73 | * proc interface -- just for compatibility |
| 89 | */ | 74 | */ |
| 90 | static int snd_seq_device_free(struct snd_seq_device *dev); | 75 | #ifdef CONFIG_PROC_FS |
| 91 | static int snd_seq_device_dev_free(struct snd_device *device); | 76 | static struct snd_info_entry *info_entry; |
| 92 | static int snd_seq_device_dev_register(struct snd_device *device); | ||
| 93 | static int snd_seq_device_dev_disconnect(struct snd_device *device); | ||
| 94 | |||
| 95 | static int init_device(struct snd_seq_device *dev, struct ops_list *ops); | ||
| 96 | static int free_device(struct snd_seq_device *dev, struct ops_list *ops); | ||
| 97 | static struct ops_list *find_driver(char *id, int create_if_empty); | ||
| 98 | static struct ops_list *create_driver(char *id); | ||
| 99 | static void unlock_driver(struct ops_list *ops); | ||
| 100 | static void remove_drivers(void); | ||
| 101 | 77 | ||
| 102 | /* | 78 | static int print_dev_info(struct device *dev, void *data) |
| 103 | * show all drivers and their status | 79 | { |
| 104 | */ | 80 | struct snd_seq_device *sdev = to_seq_dev(dev); |
| 81 | struct snd_info_buffer *buffer = data; | ||
| 82 | |||
| 83 | snd_iprintf(buffer, "snd-%s,%s,%d\n", sdev->id, | ||
| 84 | dev->driver ? "loaded" : "empty", | ||
| 85 | dev->driver ? 1 : 0); | ||
| 86 | return 0; | ||
| 87 | } | ||
| 105 | 88 | ||
| 106 | #ifdef CONFIG_PROC_FS | ||
| 107 | static void snd_seq_device_info(struct snd_info_entry *entry, | 89 | static void snd_seq_device_info(struct snd_info_entry *entry, |
| 108 | struct snd_info_buffer *buffer) | 90 | struct snd_info_buffer *buffer) |
| 109 | { | 91 | { |
| 110 | struct ops_list *ops; | 92 | bus_for_each_dev(&snd_seq_bus_type, NULL, buffer, print_dev_info); |
| 111 | |||
| 112 | mutex_lock(&ops_mutex); | ||
| 113 | list_for_each_entry(ops, &opslist, list) { | ||
| 114 | snd_iprintf(buffer, "snd-%s%s%s%s,%d\n", | ||
| 115 | ops->id, | ||
| 116 | ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""), | ||
| 117 | ops->driver & DRIVER_REQUESTED ? ",requested" : "", | ||
| 118 | ops->driver & DRIVER_LOCKED ? ",locked" : "", | ||
| 119 | ops->num_devices); | ||
| 120 | } | ||
| 121 | mutex_unlock(&ops_mutex); | ||
| 122 | } | 93 | } |
| 123 | #endif | 94 | #endif |
| 124 | 95 | ||
| 125 | /* | 96 | /* |
| 126 | * load all registered drivers (called from seq_clientmgr.c) | 97 | * load all registered drivers (called from seq_clientmgr.c) |
| 127 | */ | 98 | */ |
| 128 | 99 | ||
| 129 | #ifdef CONFIG_MODULES | 100 | #ifdef CONFIG_MODULES |
| 130 | /* avoid auto-loading during module_init() */ | 101 | /* flag to block auto-loading */ |
| 131 | static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */ | 102 | static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */ |
| 132 | void snd_seq_autoload_lock(void) | ||
| 133 | { | ||
| 134 | atomic_inc(&snd_seq_in_init); | ||
| 135 | } | ||
| 136 | 103 | ||
| 137 | void snd_seq_autoload_unlock(void) | 104 | static int request_seq_drv(struct device *dev, void *data) |
| 138 | { | 105 | { |
| 139 | atomic_dec(&snd_seq_in_init); | 106 | struct snd_seq_device *sdev = to_seq_dev(dev); |
| 107 | |||
| 108 | if (!dev->driver) | ||
| 109 | request_module("snd-%s", sdev->id); | ||
| 110 | return 0; | ||
| 140 | } | 111 | } |
| 141 | 112 | ||
| 142 | static void autoload_drivers(void) | 113 | static void autoload_drivers(struct work_struct *work) |
| 143 | { | 114 | { |
| 144 | /* avoid reentrance */ | 115 | /* avoid reentrance */ |
| 145 | if (atomic_inc_return(&snd_seq_in_init) == 1) { | 116 | if (atomic_inc_return(&snd_seq_in_init) == 1) |
| 146 | struct ops_list *ops; | 117 | bus_for_each_dev(&snd_seq_bus_type, NULL, NULL, |
| 147 | 118 | request_seq_drv); | |
| 148 | mutex_lock(&ops_mutex); | ||
| 149 | list_for_each_entry(ops, &opslist, list) { | ||
| 150 | if ((ops->driver & DRIVER_REQUESTING) && | ||
| 151 | !(ops->driver & DRIVER_REQUESTED)) { | ||
| 152 | ops->used++; | ||
| 153 | mutex_unlock(&ops_mutex); | ||
| 154 | ops->driver |= DRIVER_REQUESTED; | ||
| 155 | request_module("snd-%s", ops->id); | ||
| 156 | mutex_lock(&ops_mutex); | ||
| 157 | ops->used--; | ||
| 158 | } | ||
| 159 | } | ||
| 160 | mutex_unlock(&ops_mutex); | ||
| 161 | } | ||
| 162 | atomic_dec(&snd_seq_in_init); | 119 | atomic_dec(&snd_seq_in_init); |
| 163 | } | 120 | } |
| 164 | 121 | ||
| 165 | static void call_autoload(struct work_struct *work) | 122 | static DECLARE_WORK(autoload_work, autoload_drivers); |
| 166 | { | ||
| 167 | autoload_drivers(); | ||
| 168 | } | ||
| 169 | |||
| 170 | static DECLARE_WORK(autoload_work, call_autoload); | ||
| 171 | |||
| 172 | static void try_autoload(struct ops_list *ops) | ||
| 173 | { | ||
| 174 | if (!ops->driver) { | ||
| 175 | ops->driver |= DRIVER_REQUESTING; | ||
| 176 | schedule_work(&autoload_work); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | 123 | ||
| 180 | static void queue_autoload_drivers(void) | 124 | static void queue_autoload_drivers(void) |
| 181 | { | 125 | { |
| 182 | struct ops_list *ops; | 126 | schedule_work(&autoload_work); |
| 183 | |||
| 184 | mutex_lock(&ops_mutex); | ||
| 185 | list_for_each_entry(ops, &opslist, list) | ||
| 186 | try_autoload(ops); | ||
| 187 | mutex_unlock(&ops_mutex); | ||
| 188 | } | 127 | } |
| 189 | 128 | ||
| 190 | void snd_seq_autoload_init(void) | 129 | void snd_seq_autoload_init(void) |
| @@ -195,384 +134,143 @@ void snd_seq_autoload_init(void) | |||
| 195 | queue_autoload_drivers(); | 134 | queue_autoload_drivers(); |
| 196 | #endif | 135 | #endif |
| 197 | } | 136 | } |
| 198 | #else | 137 | EXPORT_SYMBOL(snd_seq_autoload_init); |
| 199 | #define try_autoload(ops) /* NOP */ | ||
| 200 | #endif | ||
| 201 | 138 | ||
| 202 | void snd_seq_device_load_drivers(void) | 139 | void snd_seq_autoload_exit(void) |
| 203 | { | 140 | { |
| 204 | #ifdef CONFIG_MODULES | 141 | atomic_inc(&snd_seq_in_init); |
| 205 | queue_autoload_drivers(); | ||
| 206 | flush_work(&autoload_work); | ||
| 207 | #endif | ||
| 208 | } | 142 | } |
| 143 | EXPORT_SYMBOL(snd_seq_autoload_exit); | ||
| 209 | 144 | ||
| 210 | /* | 145 | void snd_seq_device_load_drivers(void) |
| 211 | * register a sequencer device | ||
| 212 | * card = card info | ||
| 213 | * device = device number (if any) | ||
| 214 | * id = id of driver | ||
| 215 | * result = return pointer (NULL allowed if unnecessary) | ||
| 216 | */ | ||
| 217 | int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, | ||
| 218 | struct snd_seq_device **result) | ||
| 219 | { | 146 | { |
| 220 | struct snd_seq_device *dev; | 147 | queue_autoload_drivers(); |
| 221 | struct ops_list *ops; | 148 | flush_work(&autoload_work); |
| 222 | int err; | ||
| 223 | static struct snd_device_ops dops = { | ||
| 224 | .dev_free = snd_seq_device_dev_free, | ||
| 225 | .dev_register = snd_seq_device_dev_register, | ||
| 226 | .dev_disconnect = snd_seq_device_dev_disconnect, | ||
| 227 | }; | ||
| 228 | |||
| 229 | if (result) | ||
| 230 | *result = NULL; | ||
| 231 | |||
| 232 | if (snd_BUG_ON(!id)) | ||
| 233 | return -EINVAL; | ||
| 234 | |||
| 235 | ops = find_driver(id, 1); | ||
| 236 | if (ops == NULL) | ||
| 237 | return -ENOMEM; | ||
| 238 | |||
| 239 | dev = kzalloc(sizeof(*dev)*2 + argsize, GFP_KERNEL); | ||
| 240 | if (dev == NULL) { | ||
| 241 | unlock_driver(ops); | ||
| 242 | return -ENOMEM; | ||
| 243 | } | ||
| 244 | |||
| 245 | /* set up device info */ | ||
| 246 | dev->card = card; | ||
| 247 | dev->device = device; | ||
| 248 | strlcpy(dev->id, id, sizeof(dev->id)); | ||
| 249 | dev->argsize = argsize; | ||
| 250 | dev->status = SNDRV_SEQ_DEVICE_FREE; | ||
| 251 | |||
| 252 | /* add this device to the list */ | ||
| 253 | mutex_lock(&ops->reg_mutex); | ||
| 254 | list_add_tail(&dev->list, &ops->dev_list); | ||
| 255 | ops->num_devices++; | ||
| 256 | mutex_unlock(&ops->reg_mutex); | ||
| 257 | |||
| 258 | if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) { | ||
| 259 | snd_seq_device_free(dev); | ||
| 260 | return err; | ||
| 261 | } | ||
| 262 | |||
| 263 | try_autoload(ops); | ||
| 264 | unlock_driver(ops); | ||
| 265 | |||
| 266 | if (result) | ||
| 267 | *result = dev; | ||
| 268 | |||
| 269 | return 0; | ||
| 270 | } | 149 | } |
| 150 | EXPORT_SYMBOL(snd_seq_device_load_drivers); | ||
| 151 | #else | ||
| 152 | #define queue_autoload_drivers() /* NOP */ | ||
| 153 | #endif | ||
| 271 | 154 | ||
| 272 | /* | 155 | /* |
| 273 | * free the existing device | 156 | * device management |
| 274 | */ | 157 | */ |
| 275 | static int snd_seq_device_free(struct snd_seq_device *dev) | ||
| 276 | { | ||
| 277 | struct ops_list *ops; | ||
| 278 | |||
| 279 | if (snd_BUG_ON(!dev)) | ||
| 280 | return -EINVAL; | ||
| 281 | |||
| 282 | ops = find_driver(dev->id, 0); | ||
| 283 | if (ops == NULL) | ||
| 284 | return -ENXIO; | ||
| 285 | |||
| 286 | /* remove the device from the list */ | ||
| 287 | mutex_lock(&ops->reg_mutex); | ||
| 288 | list_del(&dev->list); | ||
| 289 | ops->num_devices--; | ||
| 290 | mutex_unlock(&ops->reg_mutex); | ||
| 291 | |||
| 292 | free_device(dev, ops); | ||
| 293 | if (dev->private_free) | ||
| 294 | dev->private_free(dev); | ||
| 295 | kfree(dev); | ||
| 296 | |||
| 297 | unlock_driver(ops); | ||
| 298 | |||
| 299 | return 0; | ||
| 300 | } | ||
| 301 | |||
| 302 | static int snd_seq_device_dev_free(struct snd_device *device) | 158 | static int snd_seq_device_dev_free(struct snd_device *device) |
| 303 | { | 159 | { |
| 304 | struct snd_seq_device *dev = device->device_data; | 160 | struct snd_seq_device *dev = device->device_data; |
| 305 | return snd_seq_device_free(dev); | 161 | |
| 162 | put_device(&dev->dev); | ||
| 163 | return 0; | ||
| 306 | } | 164 | } |
| 307 | 165 | ||
| 308 | /* | ||
| 309 | * register the device | ||
| 310 | */ | ||
| 311 | static int snd_seq_device_dev_register(struct snd_device *device) | 166 | static int snd_seq_device_dev_register(struct snd_device *device) |
| 312 | { | 167 | { |
| 313 | struct snd_seq_device *dev = device->device_data; | 168 | struct snd_seq_device *dev = device->device_data; |
| 314 | struct ops_list *ops; | 169 | int err; |
| 315 | |||
| 316 | ops = find_driver(dev->id, 0); | ||
| 317 | if (ops == NULL) | ||
| 318 | return -ENOENT; | ||
| 319 | |||
| 320 | /* initialize this device if the corresponding driver was | ||
| 321 | * already loaded | ||
| 322 | */ | ||
| 323 | if (ops->driver & DRIVER_LOADED) | ||
| 324 | init_device(dev, ops); | ||
| 325 | 170 | ||
| 326 | unlock_driver(ops); | 171 | err = device_add(&dev->dev); |
| 172 | if (err < 0) | ||
| 173 | return err; | ||
| 174 | if (!dev->dev.driver) | ||
| 175 | queue_autoload_drivers(); | ||
| 327 | return 0; | 176 | return 0; |
| 328 | } | 177 | } |
| 329 | 178 | ||
| 330 | /* | ||
| 331 | * disconnect the device | ||
| 332 | */ | ||
| 333 | static int snd_seq_device_dev_disconnect(struct snd_device *device) | 179 | static int snd_seq_device_dev_disconnect(struct snd_device *device) |
| 334 | { | 180 | { |
| 335 | struct snd_seq_device *dev = device->device_data; | 181 | struct snd_seq_device *dev = device->device_data; |
| 336 | struct ops_list *ops; | ||
| 337 | |||
| 338 | ops = find_driver(dev->id, 0); | ||
| 339 | if (ops == NULL) | ||
| 340 | return -ENOENT; | ||
| 341 | |||
| 342 | free_device(dev, ops); | ||
| 343 | 182 | ||
| 344 | unlock_driver(ops); | 183 | device_del(&dev->dev); |
| 345 | return 0; | 184 | return 0; |
| 346 | } | 185 | } |
| 347 | 186 | ||
| 348 | /* | 187 | static void snd_seq_dev_release(struct device *dev) |
| 349 | * register device driver | ||
| 350 | * id = driver id | ||
| 351 | * entry = driver operators - duplicated to each instance | ||
| 352 | */ | ||
| 353 | int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, | ||
| 354 | int argsize) | ||
| 355 | { | 188 | { |
| 356 | struct ops_list *ops; | 189 | struct snd_seq_device *sdev = to_seq_dev(dev); |
| 357 | struct snd_seq_device *dev; | ||
| 358 | 190 | ||
| 359 | if (id == NULL || entry == NULL || | 191 | if (sdev->private_free) |
| 360 | entry->init_device == NULL || entry->free_device == NULL) | 192 | sdev->private_free(sdev); |
| 361 | return -EINVAL; | 193 | kfree(sdev); |
| 362 | |||
| 363 | ops = find_driver(id, 1); | ||
| 364 | if (ops == NULL) | ||
| 365 | return -ENOMEM; | ||
| 366 | if (ops->driver & DRIVER_LOADED) { | ||
| 367 | pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id); | ||
| 368 | unlock_driver(ops); | ||
| 369 | return -EBUSY; | ||
| 370 | } | ||
| 371 | |||
| 372 | mutex_lock(&ops->reg_mutex); | ||
| 373 | /* copy driver operators */ | ||
| 374 | ops->ops = *entry; | ||
| 375 | ops->driver |= DRIVER_LOADED; | ||
| 376 | ops->argsize = argsize; | ||
| 377 | |||
| 378 | /* initialize existing devices if necessary */ | ||
| 379 | list_for_each_entry(dev, &ops->dev_list, list) { | ||
| 380 | init_device(dev, ops); | ||
| 381 | } | ||
| 382 | mutex_unlock(&ops->reg_mutex); | ||
| 383 | |||
| 384 | unlock_driver(ops); | ||
| 385 | |||
| 386 | return 0; | ||
| 387 | } | 194 | } |
| 388 | 195 | ||
| 389 | |||
| 390 | /* | ||
| 391 | * create driver record | ||
| 392 | */ | ||
| 393 | static struct ops_list * create_driver(char *id) | ||
| 394 | { | ||
| 395 | struct ops_list *ops; | ||
| 396 | |||
| 397 | ops = kzalloc(sizeof(*ops), GFP_KERNEL); | ||
| 398 | if (ops == NULL) | ||
| 399 | return ops; | ||
| 400 | |||
| 401 | /* set up driver entry */ | ||
| 402 | strlcpy(ops->id, id, sizeof(ops->id)); | ||
| 403 | mutex_init(&ops->reg_mutex); | ||
| 404 | /* | ||
| 405 | * The ->reg_mutex locking rules are per-driver, so we create | ||
| 406 | * separate per-driver lock classes: | ||
| 407 | */ | ||
| 408 | lockdep_set_class(&ops->reg_mutex, (struct lock_class_key *)id); | ||
| 409 | |||
| 410 | ops->driver = DRIVER_EMPTY; | ||
| 411 | INIT_LIST_HEAD(&ops->dev_list); | ||
| 412 | /* lock this instance */ | ||
| 413 | ops->used = 1; | ||
| 414 | |||
| 415 | /* register driver entry */ | ||
| 416 | mutex_lock(&ops_mutex); | ||
| 417 | list_add_tail(&ops->list, &opslist); | ||
| 418 | num_ops++; | ||
| 419 | mutex_unlock(&ops_mutex); | ||
| 420 | |||
| 421 | return ops; | ||
| 422 | } | ||
| 423 | |||
| 424 | |||
| 425 | /* | 196 | /* |
| 426 | * unregister the specified driver | 197 | * register a sequencer device |
| 198 | * card = card info | ||
| 199 | * device = device number (if any) | ||
| 200 | * id = id of driver | ||
| 201 | * result = return pointer (NULL allowed if unnecessary) | ||
| 427 | */ | 202 | */ |
| 428 | int snd_seq_device_unregister_driver(char *id) | 203 | int snd_seq_device_new(struct snd_card *card, int device, const char *id, |
| 204 | int argsize, struct snd_seq_device **result) | ||
| 429 | { | 205 | { |
| 430 | struct ops_list *ops; | ||
| 431 | struct snd_seq_device *dev; | 206 | struct snd_seq_device *dev; |
| 207 | int err; | ||
| 208 | static struct snd_device_ops dops = { | ||
| 209 | .dev_free = snd_seq_device_dev_free, | ||
| 210 | .dev_register = snd_seq_device_dev_register, | ||
| 211 | .dev_disconnect = snd_seq_device_dev_disconnect, | ||
| 212 | }; | ||
| 432 | 213 | ||
| 433 | ops = find_driver(id, 0); | 214 | if (result) |
| 434 | if (ops == NULL) | 215 | *result = NULL; |
| 435 | return -ENXIO; | ||
| 436 | if (! (ops->driver & DRIVER_LOADED) || | ||
| 437 | (ops->driver & DRIVER_LOCKED)) { | ||
| 438 | pr_err("ALSA: seq: driver_unregister: cannot unload driver '%s': status=%x\n", | ||
| 439 | id, ops->driver); | ||
| 440 | unlock_driver(ops); | ||
| 441 | return -EBUSY; | ||
| 442 | } | ||
| 443 | |||
| 444 | /* close and release all devices associated with this driver */ | ||
| 445 | mutex_lock(&ops->reg_mutex); | ||
| 446 | ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */ | ||
| 447 | list_for_each_entry(dev, &ops->dev_list, list) { | ||
| 448 | free_device(dev, ops); | ||
| 449 | } | ||
| 450 | |||
| 451 | ops->driver = 0; | ||
| 452 | if (ops->num_init_devices > 0) | ||
| 453 | pr_err("ALSA: seq: free_driver: init_devices > 0!! (%d)\n", | ||
| 454 | ops->num_init_devices); | ||
| 455 | mutex_unlock(&ops->reg_mutex); | ||
| 456 | |||
| 457 | unlock_driver(ops); | ||
| 458 | 216 | ||
| 459 | /* remove empty driver entries */ | 217 | if (snd_BUG_ON(!id)) |
| 460 | remove_drivers(); | 218 | return -EINVAL; |
| 461 | 219 | ||
| 462 | return 0; | 220 | dev = kzalloc(sizeof(*dev) + argsize, GFP_KERNEL); |
| 463 | } | 221 | if (!dev) |
| 222 | return -ENOMEM; | ||
| 464 | 223 | ||
| 224 | /* set up device info */ | ||
| 225 | dev->card = card; | ||
| 226 | dev->device = device; | ||
| 227 | dev->id = id; | ||
| 228 | dev->argsize = argsize; | ||
| 465 | 229 | ||
| 466 | /* | 230 | device_initialize(&dev->dev); |
| 467 | * remove empty driver entries | 231 | dev->dev.parent = &card->card_dev; |
| 468 | */ | 232 | dev->dev.bus = &snd_seq_bus_type; |
| 469 | static void remove_drivers(void) | 233 | dev->dev.release = snd_seq_dev_release; |
| 470 | { | 234 | dev_set_name(&dev->dev, "%s-%d-%d", dev->id, card->number, device); |
| 471 | struct list_head *head; | ||
| 472 | |||
| 473 | mutex_lock(&ops_mutex); | ||
| 474 | head = opslist.next; | ||
| 475 | while (head != &opslist) { | ||
| 476 | struct ops_list *ops = list_entry(head, struct ops_list, list); | ||
| 477 | if (! (ops->driver & DRIVER_LOADED) && | ||
| 478 | ops->used == 0 && ops->num_devices == 0) { | ||
| 479 | head = head->next; | ||
| 480 | list_del(&ops->list); | ||
| 481 | kfree(ops); | ||
| 482 | num_ops--; | ||
| 483 | } else | ||
| 484 | head = head->next; | ||
| 485 | } | ||
| 486 | mutex_unlock(&ops_mutex); | ||
| 487 | } | ||
| 488 | 235 | ||
| 489 | /* | 236 | /* add this device to the list */ |
| 490 | * initialize the device - call init_device operator | 237 | err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops); |
| 491 | */ | 238 | if (err < 0) { |
| 492 | static int init_device(struct snd_seq_device *dev, struct ops_list *ops) | 239 | put_device(&dev->dev); |
| 493 | { | 240 | return err; |
| 494 | if (! (ops->driver & DRIVER_LOADED)) | ||
| 495 | return 0; /* driver is not loaded yet */ | ||
| 496 | if (dev->status != SNDRV_SEQ_DEVICE_FREE) | ||
| 497 | return 0; /* already initialized */ | ||
| 498 | if (ops->argsize != dev->argsize) { | ||
| 499 | pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n", | ||
| 500 | dev->name, ops->id, ops->argsize, dev->argsize); | ||
| 501 | return -EINVAL; | ||
| 502 | } | ||
| 503 | if (ops->ops.init_device(dev) >= 0) { | ||
| 504 | dev->status = SNDRV_SEQ_DEVICE_REGISTERED; | ||
| 505 | ops->num_init_devices++; | ||
| 506 | } else { | ||
| 507 | pr_err("ALSA: seq: init_device failed: %s: %s\n", | ||
| 508 | dev->name, dev->id); | ||
| 509 | } | 241 | } |
| 242 | |||
| 243 | if (result) | ||
| 244 | *result = dev; | ||
| 510 | 245 | ||
| 511 | return 0; | 246 | return 0; |
| 512 | } | 247 | } |
| 248 | EXPORT_SYMBOL(snd_seq_device_new); | ||
| 513 | 249 | ||
| 514 | /* | 250 | /* |
| 515 | * release the device - call free_device operator | 251 | * driver registration |
| 516 | */ | 252 | */ |
| 517 | static int free_device(struct snd_seq_device *dev, struct ops_list *ops) | 253 | int __snd_seq_driver_register(struct snd_seq_driver *drv, struct module *mod) |
| 518 | { | 254 | { |
| 519 | int result; | 255 | if (WARN_ON(!drv->driver.name || !drv->id)) |
| 520 | |||
| 521 | if (! (ops->driver & DRIVER_LOADED)) | ||
| 522 | return 0; /* driver is not loaded yet */ | ||
| 523 | if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED) | ||
| 524 | return 0; /* not registered */ | ||
| 525 | if (ops->argsize != dev->argsize) { | ||
| 526 | pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n", | ||
| 527 | dev->name, ops->id, ops->argsize, dev->argsize); | ||
| 528 | return -EINVAL; | 256 | return -EINVAL; |
| 529 | } | 257 | drv->driver.bus = &snd_seq_bus_type; |
| 530 | if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) { | 258 | drv->driver.owner = mod; |
| 531 | dev->status = SNDRV_SEQ_DEVICE_FREE; | 259 | return driver_register(&drv->driver); |
| 532 | dev->driver_data = NULL; | ||
| 533 | ops->num_init_devices--; | ||
| 534 | } else { | ||
| 535 | pr_err("ALSA: seq: free_device failed: %s: %s\n", | ||
| 536 | dev->name, dev->id); | ||
| 537 | } | ||
| 538 | |||
| 539 | return 0; | ||
| 540 | } | 260 | } |
| 261 | EXPORT_SYMBOL_GPL(__snd_seq_driver_register); | ||
| 541 | 262 | ||
| 542 | /* | 263 | void snd_seq_driver_unregister(struct snd_seq_driver *drv) |
| 543 | * find the matching driver with given id | ||
| 544 | */ | ||
| 545 | static struct ops_list * find_driver(char *id, int create_if_empty) | ||
| 546 | { | 264 | { |
| 547 | struct ops_list *ops; | 265 | driver_unregister(&drv->driver); |
| 548 | |||
| 549 | mutex_lock(&ops_mutex); | ||
| 550 | list_for_each_entry(ops, &opslist, list) { | ||
| 551 | if (strcmp(ops->id, id) == 0) { | ||
| 552 | ops->used++; | ||
| 553 | mutex_unlock(&ops_mutex); | ||
| 554 | return ops; | ||
| 555 | } | ||
| 556 | } | ||
| 557 | mutex_unlock(&ops_mutex); | ||
| 558 | if (create_if_empty) | ||
| 559 | return create_driver(id); | ||
| 560 | return NULL; | ||
| 561 | } | 266 | } |
| 562 | 267 | EXPORT_SYMBOL_GPL(snd_seq_driver_unregister); | |
| 563 | static void unlock_driver(struct ops_list *ops) | ||
| 564 | { | ||
| 565 | mutex_lock(&ops_mutex); | ||
| 566 | ops->used--; | ||
| 567 | mutex_unlock(&ops_mutex); | ||
| 568 | } | ||
| 569 | |||
| 570 | 268 | ||
| 571 | /* | 269 | /* |
| 572 | * module part | 270 | * module part |
| 573 | */ | 271 | */ |
| 574 | 272 | ||
| 575 | static int __init alsa_seq_device_init(void) | 273 | static int __init seq_dev_proc_init(void) |
| 576 | { | 274 | { |
| 577 | #ifdef CONFIG_PROC_FS | 275 | #ifdef CONFIG_PROC_FS |
| 578 | info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers", | 276 | info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers", |
| @@ -589,28 +287,29 @@ static int __init alsa_seq_device_init(void) | |||
| 589 | return 0; | 287 | return 0; |
| 590 | } | 288 | } |
| 591 | 289 | ||
| 290 | static int __init alsa_seq_device_init(void) | ||
| 291 | { | ||
| 292 | int err; | ||
| 293 | |||
| 294 | err = bus_register(&snd_seq_bus_type); | ||
| 295 | if (err < 0) | ||
| 296 | return err; | ||
| 297 | err = seq_dev_proc_init(); | ||
| 298 | if (err < 0) | ||
| 299 | bus_unregister(&snd_seq_bus_type); | ||
| 300 | return err; | ||
| 301 | } | ||
| 302 | |||
| 592 | static void __exit alsa_seq_device_exit(void) | 303 | static void __exit alsa_seq_device_exit(void) |
| 593 | { | 304 | { |
| 594 | #ifdef CONFIG_MODULES | 305 | #ifdef CONFIG_MODULES |
| 595 | cancel_work_sync(&autoload_work); | 306 | cancel_work_sync(&autoload_work); |
| 596 | #endif | 307 | #endif |
| 597 | remove_drivers(); | ||
| 598 | #ifdef CONFIG_PROC_FS | 308 | #ifdef CONFIG_PROC_FS |
| 599 | snd_info_free_entry(info_entry); | 309 | snd_info_free_entry(info_entry); |
| 600 | #endif | 310 | #endif |
| 601 | if (num_ops) | 311 | bus_unregister(&snd_seq_bus_type); |
| 602 | pr_err("ALSA: seq: drivers not released (%d)\n", num_ops); | ||
| 603 | } | 312 | } |
| 604 | 313 | ||
| 605 | module_init(alsa_seq_device_init) | 314 | subsys_initcall(alsa_seq_device_init) |
| 606 | module_exit(alsa_seq_device_exit) | 315 | module_exit(alsa_seq_device_exit) |
| 607 | |||
| 608 | EXPORT_SYMBOL(snd_seq_device_load_drivers); | ||
| 609 | EXPORT_SYMBOL(snd_seq_device_new); | ||
| 610 | EXPORT_SYMBOL(snd_seq_device_register_driver); | ||
| 611 | EXPORT_SYMBOL(snd_seq_device_unregister_driver); | ||
| 612 | #ifdef CONFIG_MODULES | ||
| 613 | EXPORT_SYMBOL(snd_seq_autoload_init); | ||
| 614 | EXPORT_SYMBOL(snd_seq_autoload_lock); | ||
| 615 | EXPORT_SYMBOL(snd_seq_autoload_unlock); | ||
| 616 | #endif | ||
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index 5d905d90d504..d3a2ec4f0561 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c | |||
| @@ -214,11 +214,7 @@ delete_client(void) | |||
| 214 | 214 | ||
| 215 | static int __init alsa_seq_dummy_init(void) | 215 | static int __init alsa_seq_dummy_init(void) |
| 216 | { | 216 | { |
| 217 | int err; | 217 | return register_client(); |
| 218 | snd_seq_autoload_lock(); | ||
| 219 | err = register_client(); | ||
| 220 | snd_seq_autoload_unlock(); | ||
| 221 | return err; | ||
| 222 | } | 218 | } |
| 223 | 219 | ||
| 224 | static void __exit alsa_seq_dummy_exit(void) | 220 | static void __exit alsa_seq_dummy_exit(void) |
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index 53a403e17c5b..1d5acbe0c08b 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c | |||
| @@ -33,10 +33,8 @@ struct snd_seq_fifo *snd_seq_fifo_new(int poolsize) | |||
| 33 | struct snd_seq_fifo *f; | 33 | struct snd_seq_fifo *f; |
| 34 | 34 | ||
| 35 | f = kzalloc(sizeof(*f), GFP_KERNEL); | 35 | f = kzalloc(sizeof(*f), GFP_KERNEL); |
| 36 | if (f == NULL) { | 36 | if (!f) |
| 37 | pr_debug("ALSA: seq: malloc failed for snd_seq_fifo_new() \n"); | ||
| 38 | return NULL; | 37 | return NULL; |
| 39 | } | ||
| 40 | 38 | ||
| 41 | f->pool = snd_seq_pool_new(poolsize); | 39 | f->pool = snd_seq_pool_new(poolsize); |
| 42 | if (f->pool == NULL) { | 40 | if (f->pool == NULL) { |
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index ba8e4a64e13e..801076687bb1 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c | |||
| @@ -387,10 +387,8 @@ int snd_seq_pool_init(struct snd_seq_pool *pool) | |||
| 387 | return 0; | 387 | return 0; |
| 388 | 388 | ||
| 389 | pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size); | 389 | pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size); |
| 390 | if (pool->ptr == NULL) { | 390 | if (!pool->ptr) |
| 391 | pr_debug("ALSA: seq: malloc for sequencer events failed\n"); | ||
| 392 | return -ENOMEM; | 391 | return -ENOMEM; |
| 393 | } | ||
| 394 | 392 | ||
| 395 | /* add new cells to the free cell list */ | 393 | /* add new cells to the free cell list */ |
| 396 | spin_lock_irqsave(&pool->lock, flags); | 394 | spin_lock_irqsave(&pool->lock, flags); |
| @@ -463,10 +461,8 @@ struct snd_seq_pool *snd_seq_pool_new(int poolsize) | |||
| 463 | 461 | ||
| 464 | /* create pool block */ | 462 | /* create pool block */ |
| 465 | pool = kzalloc(sizeof(*pool), GFP_KERNEL); | 463 | pool = kzalloc(sizeof(*pool), GFP_KERNEL); |
| 466 | if (pool == NULL) { | 464 | if (!pool) |
| 467 | pr_debug("ALSA: seq: malloc failed for pool\n"); | ||
| 468 | return NULL; | 465 | return NULL; |
| 469 | } | ||
| 470 | spin_lock_init(&pool->lock); | 466 | spin_lock_init(&pool->lock); |
| 471 | pool->ptr = NULL; | 467 | pool->ptr = NULL; |
| 472 | pool->free = NULL; | 468 | pool->free = NULL; |
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 68fec776da26..5dd0ee258359 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c | |||
| @@ -273,8 +273,9 @@ static void snd_seq_midisynth_delete(struct seq_midisynth *msynth) | |||
| 273 | 273 | ||
| 274 | /* register new midi synth port */ | 274 | /* register new midi synth port */ |
| 275 | static int | 275 | static int |
| 276 | snd_seq_midisynth_register_port(struct snd_seq_device *dev) | 276 | snd_seq_midisynth_probe(struct device *_dev) |
| 277 | { | 277 | { |
| 278 | struct snd_seq_device *dev = to_seq_dev(_dev); | ||
| 278 | struct seq_midisynth_client *client; | 279 | struct seq_midisynth_client *client; |
| 279 | struct seq_midisynth *msynth, *ms; | 280 | struct seq_midisynth *msynth, *ms; |
| 280 | struct snd_seq_port_info *port; | 281 | struct snd_seq_port_info *port; |
| @@ -427,8 +428,9 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev) | |||
| 427 | 428 | ||
| 428 | /* release midi synth port */ | 429 | /* release midi synth port */ |
| 429 | static int | 430 | static int |
| 430 | snd_seq_midisynth_unregister_port(struct snd_seq_device *dev) | 431 | snd_seq_midisynth_remove(struct device *_dev) |
| 431 | { | 432 | { |
| 433 | struct snd_seq_device *dev = to_seq_dev(_dev); | ||
| 432 | struct seq_midisynth_client *client; | 434 | struct seq_midisynth_client *client; |
| 433 | struct seq_midisynth *msynth; | 435 | struct seq_midisynth *msynth; |
| 434 | struct snd_card *card = dev->card; | 436 | struct snd_card *card = dev->card; |
| @@ -457,24 +459,14 @@ snd_seq_midisynth_unregister_port(struct snd_seq_device *dev) | |||
| 457 | return 0; | 459 | return 0; |
| 458 | } | 460 | } |
| 459 | 461 | ||
| 462 | static struct snd_seq_driver seq_midisynth_driver = { | ||
| 463 | .driver = { | ||
| 464 | .name = KBUILD_MODNAME, | ||
| 465 | .probe = snd_seq_midisynth_probe, | ||
| 466 | .remove = snd_seq_midisynth_remove, | ||
| 467 | }, | ||
| 468 | .id = SNDRV_SEQ_DEV_ID_MIDISYNTH, | ||
| 469 | .argsize = 0, | ||
| 470 | }; | ||
| 460 | 471 | ||
| 461 | static int __init alsa_seq_midi_init(void) | 472 | module_snd_seq_driver(seq_midisynth_driver); |
| 462 | { | ||
| 463 | static struct snd_seq_dev_ops ops = { | ||
| 464 | snd_seq_midisynth_register_port, | ||
| 465 | snd_seq_midisynth_unregister_port, | ||
| 466 | }; | ||
| 467 | memset(&synths, 0, sizeof(synths)); | ||
| 468 | snd_seq_autoload_lock(); | ||
| 469 | snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH, &ops, 0); | ||
| 470 | snd_seq_autoload_unlock(); | ||
| 471 | return 0; | ||
| 472 | } | ||
| 473 | |||
| 474 | static void __exit alsa_seq_midi_exit(void) | ||
| 475 | { | ||
| 476 | snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH); | ||
| 477 | } | ||
| 478 | |||
| 479 | module_init(alsa_seq_midi_init) | ||
| 480 | module_exit(alsa_seq_midi_exit) | ||
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 46ff593f618d..55170a20ae72 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c | |||
| @@ -141,10 +141,8 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, | |||
| 141 | 141 | ||
| 142 | /* create a new port */ | 142 | /* create a new port */ |
| 143 | new_port = kzalloc(sizeof(*new_port), GFP_KERNEL); | 143 | new_port = kzalloc(sizeof(*new_port), GFP_KERNEL); |
| 144 | if (! new_port) { | 144 | if (!new_port) |
| 145 | pr_debug("ALSA: seq: malloc failed for registering client port\n"); | ||
| 146 | return NULL; /* failure, out of memory */ | 145 | return NULL; /* failure, out of memory */ |
| 147 | } | ||
| 148 | /* init port data */ | 146 | /* init port data */ |
| 149 | new_port->addr.client = client->number; | 147 | new_port->addr.client = client->number; |
| 150 | new_port->addr.port = -1; | 148 | new_port->addr.port = -1; |
diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c index 021b02bc9330..bc1c8488fc2a 100644 --- a/sound/core/seq/seq_prioq.c +++ b/sound/core/seq/seq_prioq.c | |||
| @@ -59,10 +59,8 @@ struct snd_seq_prioq *snd_seq_prioq_new(void) | |||
| 59 | struct snd_seq_prioq *f; | 59 | struct snd_seq_prioq *f; |
| 60 | 60 | ||
| 61 | f = kzalloc(sizeof(*f), GFP_KERNEL); | 61 | f = kzalloc(sizeof(*f), GFP_KERNEL); |
| 62 | if (f == NULL) { | 62 | if (!f) |
| 63 | pr_debug("ALSA: seq: malloc failed for snd_seq_prioq_new()\n"); | ||
| 64 | return NULL; | 63 | return NULL; |
| 65 | } | ||
| 66 | 64 | ||
| 67 | spin_lock_init(&f->lock); | 65 | spin_lock_init(&f->lock); |
| 68 | f->head = NULL; | 66 | f->head = NULL; |
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index aad4878cee55..a0cda38205b9 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c | |||
| @@ -111,10 +111,8 @@ static struct snd_seq_queue *queue_new(int owner, int locked) | |||
| 111 | struct snd_seq_queue *q; | 111 | struct snd_seq_queue *q; |
| 112 | 112 | ||
| 113 | q = kzalloc(sizeof(*q), GFP_KERNEL); | 113 | q = kzalloc(sizeof(*q), GFP_KERNEL); |
| 114 | if (q == NULL) { | 114 | if (!q) |
| 115 | pr_debug("ALSA: seq: malloc failed for snd_seq_queue_new()\n"); | ||
| 116 | return NULL; | 115 | return NULL; |
| 117 | } | ||
| 118 | 116 | ||
| 119 | spin_lock_init(&q->owner_lock); | 117 | spin_lock_init(&q->owner_lock); |
| 120 | spin_lock_init(&q->check_lock); | 118 | spin_lock_init(&q->check_lock); |
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index e73605393eee..186f1611103c 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c | |||
| @@ -56,10 +56,8 @@ struct snd_seq_timer *snd_seq_timer_new(void) | |||
| 56 | struct snd_seq_timer *tmr; | 56 | struct snd_seq_timer *tmr; |
| 57 | 57 | ||
| 58 | tmr = kzalloc(sizeof(*tmr), GFP_KERNEL); | 58 | tmr = kzalloc(sizeof(*tmr), GFP_KERNEL); |
| 59 | if (tmr == NULL) { | 59 | if (!tmr) |
| 60 | pr_debug("ALSA: seq: malloc failed for snd_seq_timer_new() \n"); | ||
| 61 | return NULL; | 60 | return NULL; |
| 62 | } | ||
| 63 | spin_lock_init(&tmr->lock); | 61 | spin_lock_init(&tmr->lock); |
| 64 | 62 | ||
| 65 | /* reset setup to defaults */ | 63 | /* reset setup to defaults */ |
diff --git a/sound/core/sound.c b/sound/core/sound.c index 185cec01ee25..5fc93d00572a 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c | |||
| @@ -186,7 +186,7 @@ static const struct file_operations snd_fops = | |||
| 186 | }; | 186 | }; |
| 187 | 187 | ||
| 188 | #ifdef CONFIG_SND_DYNAMIC_MINORS | 188 | #ifdef CONFIG_SND_DYNAMIC_MINORS |
| 189 | static int snd_find_free_minor(int type) | 189 | static int snd_find_free_minor(int type, struct snd_card *card, int dev) |
| 190 | { | 190 | { |
| 191 | int minor; | 191 | int minor; |
| 192 | 192 | ||
| @@ -209,7 +209,7 @@ static int snd_find_free_minor(int type) | |||
| 209 | return -EBUSY; | 209 | return -EBUSY; |
| 210 | } | 210 | } |
| 211 | #else | 211 | #else |
| 212 | static int snd_kernel_minor(int type, struct snd_card *card, int dev) | 212 | static int snd_find_free_minor(int type, struct snd_card *card, int dev) |
| 213 | { | 213 | { |
| 214 | int minor; | 214 | int minor; |
| 215 | 215 | ||
| @@ -237,6 +237,8 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev) | |||
| 237 | } | 237 | } |
| 238 | if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS)) | 238 | if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS)) |
| 239 | return -EINVAL; | 239 | return -EINVAL; |
| 240 | if (snd_minors[minor]) | ||
| 241 | return -EBUSY; | ||
| 240 | return minor; | 242 | return minor; |
| 241 | } | 243 | } |
| 242 | #endif | 244 | #endif |
| @@ -276,13 +278,7 @@ int snd_register_device(int type, struct snd_card *card, int dev, | |||
| 276 | preg->private_data = private_data; | 278 | preg->private_data = private_data; |
| 277 | preg->card_ptr = card; | 279 | preg->card_ptr = card; |
| 278 | mutex_lock(&sound_mutex); | 280 | mutex_lock(&sound_mutex); |
| 279 | #ifdef CONFIG_SND_DYNAMIC_MINORS | 281 | minor = snd_find_free_minor(type, card, dev); |
| 280 | minor = snd_find_free_minor(type); | ||
| 281 | #else | ||
| 282 | minor = snd_kernel_minor(type, card, dev); | ||
| 283 | if (minor >= 0 && snd_minors[minor]) | ||
| 284 | minor = -EBUSY; | ||
| 285 | #endif | ||
| 286 | if (minor < 0) { | 282 | if (minor < 0) { |
| 287 | err = minor; | 283 | err = minor; |
| 288 | goto error; | 284 | goto error; |
diff --git a/sound/core/timer.c b/sound/core/timer.c index 490b489d713d..a9a1a047c521 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
| @@ -774,10 +774,8 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, | |||
| 774 | if (rtimer) | 774 | if (rtimer) |
| 775 | *rtimer = NULL; | 775 | *rtimer = NULL; |
| 776 | timer = kzalloc(sizeof(*timer), GFP_KERNEL); | 776 | timer = kzalloc(sizeof(*timer), GFP_KERNEL); |
| 777 | if (timer == NULL) { | 777 | if (!timer) |
| 778 | pr_err("ALSA: timer: cannot allocate\n"); | ||
| 779 | return -ENOMEM; | 778 | return -ENOMEM; |
| 780 | } | ||
| 781 | timer->tmr_class = tid->dev_class; | 779 | timer->tmr_class = tid->dev_class; |
| 782 | timer->card = card; | 780 | timer->card = card; |
| 783 | timer->tmr_device = tid->device; | 781 | timer->tmr_device = tid->device; |
