diff options
author | Andrew de Quincey <adq_dvb@lidskialf.net> | 2005-12-01 03:51:49 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-12-01 18:48:58 -0500 |
commit | ded928468407c8e08dcb6aedb91aaa97b80d5752 (patch) | |
tree | 2b85f26bc526939697f3f5192e3ea4385577bdd7 | |
parent | 69459f3d2fb9eea370535ceba91dd8c9df3d94bc (diff) |
[PATCH] DVB: Fix locking problems and code cleanup
Fix locking problems and code cleanup
Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net>
Signed-off-by: Johannes Stezenbach <js@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 69 |
1 files changed, 23 insertions, 46 deletions
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 2aa767f9bd7d..cb2e7d6ba283 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c | |||
@@ -35,7 +35,7 @@ | |||
35 | #include <linux/moduleparam.h> | 35 | #include <linux/moduleparam.h> |
36 | #include <linux/vmalloc.h> | 36 | #include <linux/vmalloc.h> |
37 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
38 | #include <linux/rwsem.h> | 38 | #include <linux/spinlock.h> |
39 | #include <linux/sched.h> | 39 | #include <linux/sched.h> |
40 | 40 | ||
41 | #include "dvb_ca_en50221.h" | 41 | #include "dvb_ca_en50221.h" |
@@ -111,9 +111,6 @@ struct dvb_ca_slot { | |||
111 | /* size of the buffer to use when talking to the CAM */ | 111 | /* size of the buffer to use when talking to the CAM */ |
112 | int link_buf_size; | 112 | int link_buf_size; |
113 | 113 | ||
114 | /* semaphore for syncing access to slot structure */ | ||
115 | struct rw_semaphore sem; | ||
116 | |||
117 | /* buffer for incoming packets */ | 114 | /* buffer for incoming packets */ |
118 | struct dvb_ringbuffer rx_buffer; | 115 | struct dvb_ringbuffer rx_buffer; |
119 | 116 | ||
@@ -602,14 +599,11 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * eb | |||
602 | if (ebuf == NULL) { | 599 | if (ebuf == NULL) { |
603 | int buf_free; | 600 | int buf_free; |
604 | 601 | ||
605 | down_read(&ca->slot_info[slot].sem); | ||
606 | if (ca->slot_info[slot].rx_buffer.data == NULL) { | 602 | if (ca->slot_info[slot].rx_buffer.data == NULL) { |
607 | up_read(&ca->slot_info[slot].sem); | ||
608 | status = -EIO; | 603 | status = -EIO; |
609 | goto exit; | 604 | goto exit; |
610 | } | 605 | } |
611 | buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer); | 606 | buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer); |
612 | up_read(&ca->slot_info[slot].sem); | ||
613 | 607 | ||
614 | if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) { | 608 | if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) { |
615 | status = -EAGAIN; | 609 | status = -EAGAIN; |
@@ -680,14 +674,11 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * eb | |||
680 | 674 | ||
681 | /* OK, add it to the receive buffer, or copy into external buffer if supplied */ | 675 | /* OK, add it to the receive buffer, or copy into external buffer if supplied */ |
682 | if (ebuf == NULL) { | 676 | if (ebuf == NULL) { |
683 | down_read(&ca->slot_info[slot].sem); | ||
684 | if (ca->slot_info[slot].rx_buffer.data == NULL) { | 677 | if (ca->slot_info[slot].rx_buffer.data == NULL) { |
685 | up_read(&ca->slot_info[slot].sem); | ||
686 | status = -EIO; | 678 | status = -EIO; |
687 | goto exit; | 679 | goto exit; |
688 | } | 680 | } |
689 | dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read); | 681 | dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read); |
690 | up_read(&ca->slot_info[slot].sem); | ||
691 | } else { | 682 | } else { |
692 | memcpy(ebuf, buf, bytes_read); | 683 | memcpy(ebuf, buf, bytes_read); |
693 | } | 684 | } |
@@ -802,12 +793,8 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot) | |||
802 | { | 793 | { |
803 | dprintk("%s\n", __FUNCTION__); | 794 | dprintk("%s\n", __FUNCTION__); |
804 | 795 | ||
805 | down_write(&ca->slot_info[slot].sem); | ||
806 | ca->pub->slot_shutdown(ca->pub, slot); | 796 | ca->pub->slot_shutdown(ca->pub, slot); |
807 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; | 797 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; |
808 | vfree(ca->slot_info[slot].rx_buffer.data); | ||
809 | ca->slot_info[slot].rx_buffer.data = NULL; | ||
810 | up_write(&ca->slot_info[slot].sem); | ||
811 | 798 | ||
812 | /* need to wake up all processes to check if they're now | 799 | /* need to wake up all processes to check if they're now |
813 | trying to write to a defunct CAM */ | 800 | trying to write to a defunct CAM */ |
@@ -893,7 +880,7 @@ void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot) | |||
893 | 880 | ||
894 | case DVB_CA_SLOTSTATE_RUNNING: | 881 | case DVB_CA_SLOTSTATE_RUNNING: |
895 | if (ca->open) | 882 | if (ca->open) |
896 | dvb_ca_en50221_read_data(ca, slot, NULL, 0); | 883 | dvb_ca_en50221_thread_wakeup(ca); |
897 | break; | 884 | break; |
898 | } | 885 | } |
899 | } | 886 | } |
@@ -1127,16 +1114,16 @@ static int dvb_ca_en50221_thread(void *data) | |||
1127 | break; | 1114 | break; |
1128 | } | 1115 | } |
1129 | 1116 | ||
1130 | rxbuf = vmalloc(RX_BUFFER_SIZE); | 1117 | if (ca->slot_info[slot].rx_buffer.data == NULL) { |
1131 | if (rxbuf == NULL) { | 1118 | rxbuf = vmalloc(RX_BUFFER_SIZE); |
1132 | printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num); | 1119 | if (rxbuf == NULL) { |
1133 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; | 1120 | printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num); |
1134 | dvb_ca_en50221_thread_update_delay(ca); | 1121 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; |
1135 | break; | 1122 | dvb_ca_en50221_thread_update_delay(ca); |
1123 | break; | ||
1124 | } | ||
1125 | dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE); | ||
1136 | } | 1126 | } |
1137 | down_write(&ca->slot_info[slot].sem); | ||
1138 | dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE); | ||
1139 | up_write(&ca->slot_info[slot].sem); | ||
1140 | 1127 | ||
1141 | ca->pub->slot_ts_enable(ca->pub, slot); | 1128 | ca->pub->slot_ts_enable(ca->pub, slot); |
1142 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING; | 1129 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING; |
@@ -1148,11 +1135,7 @@ static int dvb_ca_en50221_thread(void *data) | |||
1148 | if (!ca->open) | 1135 | if (!ca->open) |
1149 | continue; | 1136 | continue; |
1150 | 1137 | ||
1151 | // no need to poll if the CAM supports IRQs | 1138 | // poll slots for data |
1152 | if (ca->slot_info[slot].da_irq_supported) | ||
1153 | break; | ||
1154 | |||
1155 | // poll mode | ||
1156 | pktcount = 0; | 1139 | pktcount = 0; |
1157 | while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) { | 1140 | while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) { |
1158 | if (!ca->open) | 1141 | if (!ca->open) |
@@ -1367,12 +1350,13 @@ exit: | |||
1367 | /** | 1350 | /** |
1368 | * Condition for waking up in dvb_ca_en50221_io_read_condition | 1351 | * Condition for waking up in dvb_ca_en50221_io_read_condition |
1369 | */ | 1352 | */ |
1370 | static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, int *result, int *_slot) | 1353 | static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, |
1354 | int *result, int *_slot) | ||
1371 | { | 1355 | { |
1372 | int slot; | 1356 | int slot; |
1373 | int slot_count = 0; | 1357 | int slot_count = 0; |
1374 | int idx; | 1358 | int idx; |
1375 | int fraglen; | 1359 | size_t fraglen; |
1376 | int connection_id = -1; | 1360 | int connection_id = -1; |
1377 | int found = 0; | 1361 | int found = 0; |
1378 | u8 hdr[2]; | 1362 | u8 hdr[2]; |
@@ -1382,10 +1366,7 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, int *resu | |||
1382 | if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) | 1366 | if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) |
1383 | goto nextslot; | 1367 | goto nextslot; |
1384 | 1368 | ||
1385 | down_read(&ca->slot_info[slot].sem); | ||
1386 | |||
1387 | if (ca->slot_info[slot].rx_buffer.data == NULL) { | 1369 | if (ca->slot_info[slot].rx_buffer.data == NULL) { |
1388 | up_read(&ca->slot_info[slot].sem); | ||
1389 | return 0; | 1370 | return 0; |
1390 | } | 1371 | } |
1391 | 1372 | ||
@@ -1403,10 +1384,7 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, int *resu | |||
1403 | idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); | 1384 | idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); |
1404 | } | 1385 | } |
1405 | 1386 | ||
1406 | if (!found) | 1387 | nextslot: |
1407 | up_read(&ca->slot_info[slot].sem); | ||
1408 | |||
1409 | nextslot: | ||
1410 | slot = (slot + 1) % ca->slot_count; | 1388 | slot = (slot + 1) % ca->slot_count; |
1411 | slot_count++; | 1389 | slot_count++; |
1412 | } | 1390 | } |
@@ -1511,8 +1489,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf, | |||
1511 | goto exit; | 1489 | goto exit; |
1512 | status = pktlen; | 1490 | status = pktlen; |
1513 | 1491 | ||
1514 | exit: | 1492 | exit: |
1515 | up_read(&ca->slot_info[slot].sem); | ||
1516 | return status; | 1493 | return status; |
1517 | } | 1494 | } |
1518 | 1495 | ||
@@ -1544,11 +1521,11 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) | |||
1544 | for (i = 0; i < ca->slot_count; i++) { | 1521 | for (i = 0; i < ca->slot_count; i++) { |
1545 | 1522 | ||
1546 | if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) { | 1523 | if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) { |
1547 | down_write(&ca->slot_info[i].sem); | ||
1548 | if (ca->slot_info[i].rx_buffer.data != NULL) { | 1524 | if (ca->slot_info[i].rx_buffer.data != NULL) { |
1525 | /* it is safe to call this here without locks because | ||
1526 | * ca->open == 0. Data is not read in this case */ | ||
1549 | dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer); | 1527 | dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer); |
1550 | } | 1528 | } |
1551 | up_write(&ca->slot_info[i].sem); | ||
1552 | } | 1529 | } |
1553 | } | 1530 | } |
1554 | 1531 | ||
@@ -1607,7 +1584,6 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait) | |||
1607 | dprintk("%s\n", __FUNCTION__); | 1584 | dprintk("%s\n", __FUNCTION__); |
1608 | 1585 | ||
1609 | if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { | 1586 | if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { |
1610 | up_read(&ca->slot_info[slot].sem); | ||
1611 | mask |= POLLIN; | 1587 | mask |= POLLIN; |
1612 | } | 1588 | } |
1613 | 1589 | ||
@@ -1619,7 +1595,6 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait) | |||
1619 | poll_wait(file, &ca->wait_queue, wait); | 1595 | poll_wait(file, &ca->wait_queue, wait); |
1620 | 1596 | ||
1621 | if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { | 1597 | if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { |
1622 | up_read(&ca->slot_info[slot].sem); | ||
1623 | mask |= POLLIN; | 1598 | mask |= POLLIN; |
1624 | } | 1599 | } |
1625 | 1600 | ||
@@ -1709,7 +1684,6 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, | |||
1709 | ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; | 1684 | ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; |
1710 | atomic_set(&ca->slot_info[i].camchange_count, 0); | 1685 | atomic_set(&ca->slot_info[i].camchange_count, 0); |
1711 | ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; | 1686 | ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; |
1712 | init_rwsem(&ca->slot_info[i].sem); | ||
1713 | } | 1687 | } |
1714 | 1688 | ||
1715 | if (signal_pending(current)) { | 1689 | if (signal_pending(current)) { |
@@ -1729,7 +1703,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, | |||
1729 | ca->thread_pid = ret; | 1703 | ca->thread_pid = ret; |
1730 | return 0; | 1704 | return 0; |
1731 | 1705 | ||
1732 | error: | 1706 | error: |
1733 | if (ca != NULL) { | 1707 | if (ca != NULL) { |
1734 | if (ca->dvbdev != NULL) | 1708 | if (ca->dvbdev != NULL) |
1735 | dvb_unregister_device(ca->dvbdev); | 1709 | dvb_unregister_device(ca->dvbdev); |
@@ -1771,6 +1745,9 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) | |||
1771 | 1745 | ||
1772 | for (i = 0; i < ca->slot_count; i++) { | 1746 | for (i = 0; i < ca->slot_count; i++) { |
1773 | dvb_ca_en50221_slot_shutdown(ca, i); | 1747 | dvb_ca_en50221_slot_shutdown(ca, i); |
1748 | if (ca->slot_info[i].rx_buffer.data != NULL) { | ||
1749 | vfree(ca->slot_info[i].rx_buffer.data); | ||
1750 | } | ||
1774 | } | 1751 | } |
1775 | kfree(ca->slot_info); | 1752 | kfree(ca->slot_info); |
1776 | dvb_unregister_device(ca->dvbdev); | 1753 | dvb_unregister_device(ca->dvbdev); |