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); |
