aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/radio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/radio')
-rw-r--r--drivers/media/radio/radio-si470x.c84
1 files changed, 41 insertions, 43 deletions
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
index 5dd33197bbdd..707988edc1b1 100644
--- a/drivers/media/radio/radio-si470x.c
+++ b/drivers/media/radio/radio-si470x.c
@@ -85,7 +85,7 @@
85 * Oliver Neukum <oliver@neukum.org> 85 * Oliver Neukum <oliver@neukum.org>
86 * Version 1.0.7 86 * Version 1.0.7
87 * - usb autosuspend support 87 * - usb autosuspend support
88 * - unplugging fixed 88 * - unplugging fixed
89 * 89 *
90 * ToDo: 90 * ToDo:
91 * - add seeking support 91 * - add seeking support
@@ -425,7 +425,8 @@ struct si470x_device {
425 425
426 /* driver management */ 426 /* driver management */
427 unsigned int users; 427 unsigned int users;
428 unsigned char disconnected; 428 unsigned char disconnected;
429 struct mutex disconnect_lock;
429 430
430 /* Silabs internal registers (0..15) */ 431 /* Silabs internal registers (0..15) */
431 unsigned short registers[RADIO_REGISTER_NUM]; 432 unsigned short registers[RADIO_REGISTER_NUM];
@@ -442,12 +443,6 @@ struct si470x_device {
442 443
443 444
444/* 445/*
445 * Lock to prevent kfree of data before all users have releases the device.
446 */
447static DEFINE_MUTEX(open_close_lock);
448
449
450/*
451 * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW, 446 * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
452 * 62.5 kHz otherwise. 447 * 62.5 kHz otherwise.
453 * The tuner is able to have a channel spacing of 50, 100 or 200 kHz. 448 * The tuner is able to have a channel spacing of 50, 100 or 200 kHz.
@@ -582,7 +577,7 @@ static int si470x_get_rds_registers(struct si470x_device *radio)
582 usb_rcvintpipe(radio->usbdev, 1), 577 usb_rcvintpipe(radio->usbdev, 1),
583 (void *) &buf, sizeof(buf), &size, usb_timeout); 578 (void *) &buf, sizeof(buf), &size, usb_timeout);
584 if (size != sizeof(buf)) 579 if (size != sizeof(buf))
585 printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: " 580 printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
586 "return size differs: %d != %zu\n", size, sizeof(buf)); 581 "return size differs: %d != %zu\n", size, sizeof(buf));
587 if (retval < 0) 582 if (retval < 0)
588 printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: " 583 printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
@@ -591,7 +586,8 @@ static int si470x_get_rds_registers(struct si470x_device *radio)
591 if (retval >= 0) 586 if (retval >= 0)
592 for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) 587 for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
593 radio->registers[STATUSRSSI + regnr] = 588 radio->registers[STATUSRSSI + regnr] =
594 get_unaligned_be16(&buf[regnr * RADIO_REGISTER_SIZE + 1]); 589 get_unaligned_be16(
590 &buf[regnr * RADIO_REGISTER_SIZE + 1]);
595 591
596 return (retval < 0) ? -EINVAL : 0; 592 return (retval < 0) ? -EINVAL : 0;
597} 593}
@@ -879,8 +875,8 @@ static void si470x_work(struct work_struct *work)
879 struct si470x_device *radio = container_of(work, struct si470x_device, 875 struct si470x_device *radio = container_of(work, struct si470x_device,
880 work.work); 876 work.work);
881 877
882 if (radio->disconnected) 878 if (radio->disconnected)
883 return; 879 return;
884 if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) 880 if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
885 return; 881 return;
886 882
@@ -1007,20 +1003,20 @@ static int si470x_fops_open(struct inode *inode, struct file *file)
1007static int si470x_fops_release(struct inode *inode, struct file *file) 1003static int si470x_fops_release(struct inode *inode, struct file *file)
1008{ 1004{
1009 struct si470x_device *radio = video_get_drvdata(video_devdata(file)); 1005 struct si470x_device *radio = video_get_drvdata(video_devdata(file));
1010 int retval = 0; 1006 int retval = 0;
1011 1007
1012 if (!radio) 1008 if (!radio)
1013 return -ENODEV; 1009 return -ENODEV;
1014 1010
1015 mutex_lock(&open_close_lock); 1011 mutex_lock(&radio->disconnect_lock);
1016 radio->users--; 1012 radio->users--;
1017 if (radio->users == 0) { 1013 if (radio->users == 0) {
1018 if (radio->disconnected) { 1014 if (radio->disconnected) {
1019 video_unregister_device(radio->videodev); 1015 video_unregister_device(radio->videodev);
1020 kfree(radio->buffer); 1016 kfree(radio->buffer);
1021 kfree(radio); 1017 kfree(radio);
1022 goto done; 1018 goto unlock;
1023 } 1019 }
1024 1020
1025 /* stop rds reception */ 1021 /* stop rds reception */
1026 cancel_delayed_work_sync(&radio->work); 1022 cancel_delayed_work_sync(&radio->work);
@@ -1032,9 +1028,9 @@ static int si470x_fops_release(struct inode *inode, struct file *file)
1032 usb_autopm_put_interface(radio->intf); 1028 usb_autopm_put_interface(radio->intf);
1033 } 1029 }
1034 1030
1035done: 1031unlock:
1036 mutex_unlock(&open_close_lock); 1032 mutex_unlock(&radio->disconnect_lock);
1037 return retval; 1033 return retval;
1038} 1034}
1039 1035
1040 1036
@@ -1174,8 +1170,8 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
1174{ 1170{
1175 struct si470x_device *radio = video_get_drvdata(video_devdata(file)); 1171 struct si470x_device *radio = video_get_drvdata(video_devdata(file));
1176 1172
1177 if (radio->disconnected) 1173 if (radio->disconnected)
1178 return -EIO; 1174 return -EIO;
1179 1175
1180 switch (ctrl->id) { 1176 switch (ctrl->id) {
1181 case V4L2_CID_AUDIO_VOLUME: 1177 case V4L2_CID_AUDIO_VOLUME:
@@ -1201,8 +1197,8 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
1201 struct si470x_device *radio = video_get_drvdata(video_devdata(file)); 1197 struct si470x_device *radio = video_get_drvdata(video_devdata(file));
1202 int retval; 1198 int retval;
1203 1199
1204 if (radio->disconnected) 1200 if (radio->disconnected)
1205 return -EIO; 1201 return -EIO;
1206 1202
1207 switch (ctrl->id) { 1203 switch (ctrl->id) {
1208 case V4L2_CID_AUDIO_VOLUME: 1204 case V4L2_CID_AUDIO_VOLUME:
@@ -1266,8 +1262,8 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
1266 struct si470x_device *radio = video_get_drvdata(video_devdata(file)); 1262 struct si470x_device *radio = video_get_drvdata(video_devdata(file));
1267 int retval; 1263 int retval;
1268 1264
1269 if (radio->disconnected) 1265 if (radio->disconnected)
1270 return -EIO; 1266 return -EIO;
1271 if (tuner->index > 0) 1267 if (tuner->index > 0)
1272 return -EINVAL; 1268 return -EINVAL;
1273 1269
@@ -1324,8 +1320,8 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
1324 struct si470x_device *radio = video_get_drvdata(video_devdata(file)); 1320 struct si470x_device *radio = video_get_drvdata(video_devdata(file));
1325 int retval; 1321 int retval;
1326 1322
1327 if (radio->disconnected) 1323 if (radio->disconnected)
1328 return -EIO; 1324 return -EIO;
1329 if (tuner->index > 0) 1325 if (tuner->index > 0)
1330 return -EINVAL; 1326 return -EINVAL;
1331 1327
@@ -1351,8 +1347,8 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv,
1351{ 1347{
1352 struct si470x_device *radio = video_get_drvdata(video_devdata(file)); 1348 struct si470x_device *radio = video_get_drvdata(video_devdata(file));
1353 1349
1354 if (radio->disconnected) 1350 if (radio->disconnected)
1355 return -EIO; 1351 return -EIO;
1356 1352
1357 freq->type = V4L2_TUNER_RADIO; 1353 freq->type = V4L2_TUNER_RADIO;
1358 freq->frequency = si470x_get_freq(radio); 1354 freq->frequency = si470x_get_freq(radio);
@@ -1370,8 +1366,8 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv,
1370 struct si470x_device *radio = video_get_drvdata(video_devdata(file)); 1366 struct si470x_device *radio = video_get_drvdata(video_devdata(file));
1371 int retval; 1367 int retval;
1372 1368
1373 if (radio->disconnected) 1369 if (radio->disconnected)
1374 return -EIO; 1370 return -EIO;
1375 if (freq->type != V4L2_TUNER_RADIO) 1371 if (freq->type != V4L2_TUNER_RADIO)
1376 return -EINVAL; 1372 return -EINVAL;
1377 1373
@@ -1436,8 +1432,10 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
1436 memcpy(radio->videodev, &si470x_viddev_template, 1432 memcpy(radio->videodev, &si470x_viddev_template,
1437 sizeof(si470x_viddev_template)); 1433 sizeof(si470x_viddev_template));
1438 radio->users = 0; 1434 radio->users = 0;
1435 radio->disconnected = 0;
1439 radio->usbdev = interface_to_usbdev(intf); 1436 radio->usbdev = interface_to_usbdev(intf);
1440 radio->intf = intf; 1437 radio->intf = intf;
1438 mutex_init(&radio->disconnect_lock);
1441 mutex_init(&radio->lock); 1439 mutex_init(&radio->lock);
1442 video_set_drvdata(radio->videodev, radio); 1440 video_set_drvdata(radio->videodev, radio);
1443 1441
@@ -1542,16 +1540,16 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
1542{ 1540{
1543 struct si470x_device *radio = usb_get_intfdata(intf); 1541 struct si470x_device *radio = usb_get_intfdata(intf);
1544 1542
1545 mutex_lock(&open_close_lock); 1543 mutex_lock(&radio->disconnect_lock);
1546 radio->disconnected = 1; 1544 radio->disconnected = 1;
1547 cancel_delayed_work_sync(&radio->work); 1545 cancel_delayed_work_sync(&radio->work);
1548 usb_set_intfdata(intf, NULL); 1546 usb_set_intfdata(intf, NULL);
1549 if (radio->users == 0) { 1547 if (radio->users == 0) {
1550 video_unregister_device(radio->videodev); 1548 video_unregister_device(radio->videodev);
1551 kfree(radio->buffer); 1549 kfree(radio->buffer);
1552 kfree(radio); 1550 kfree(radio);
1553 } 1551 }
1554 mutex_unlock(&open_close_lock); 1552 mutex_unlock(&radio->disconnect_lock);
1555} 1553}
1556 1554
1557 1555