diff options
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 24 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-core/dvb_ca_en50221.h | 6 |
2 files changed, 25 insertions, 5 deletions
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 98ee16773ff2..7e3aeaa7370f 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c | |||
@@ -93,6 +93,9 @@ struct dvb_ca_slot { | |||
93 | /* current state of the CAM */ | 93 | /* current state of the CAM */ |
94 | int slot_state; | 94 | int slot_state; |
95 | 95 | ||
96 | /* mutex used for serializing access to one CI slot */ | ||
97 | struct mutex slot_lock; | ||
98 | |||
96 | /* Number of CAMCHANGES that have occurred since last processing */ | 99 | /* Number of CAMCHANGES that have occurred since last processing */ |
97 | atomic_t camchange_count; | 100 | atomic_t camchange_count; |
98 | 101 | ||
@@ -711,14 +714,20 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * b | |||
711 | dprintk("%s\n", __func__); | 714 | dprintk("%s\n", __func__); |
712 | 715 | ||
713 | 716 | ||
714 | // sanity check | 717 | /* sanity check */ |
715 | if (bytes_write > ca->slot_info[slot].link_buf_size) | 718 | if (bytes_write > ca->slot_info[slot].link_buf_size) |
716 | return -EINVAL; | 719 | return -EINVAL; |
717 | 720 | ||
718 | /* check if interface is actually waiting for us to read from it, or if a read is in progress */ | 721 | /* it is possible we are dealing with a single buffer implementation, |
722 | thus if there is data available for read or if there is even a read | ||
723 | already in progress, we do nothing but awake the kernel thread to | ||
724 | process the data if necessary. */ | ||
719 | if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) | 725 | if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) |
720 | goto exitnowrite; | 726 | goto exitnowrite; |
721 | if (status & (STATUSREG_DA | STATUSREG_RE)) { | 727 | if (status & (STATUSREG_DA | STATUSREG_RE)) { |
728 | if (status & STATUSREG_DA) | ||
729 | dvb_ca_en50221_thread_wakeup(ca); | ||
730 | |||
722 | status = -EAGAIN; | 731 | status = -EAGAIN; |
723 | goto exitnowrite; | 732 | goto exitnowrite; |
724 | } | 733 | } |
@@ -987,6 +996,8 @@ static int dvb_ca_en50221_thread(void *data) | |||
987 | /* go through all the slots processing them */ | 996 | /* go through all the slots processing them */ |
988 | for (slot = 0; slot < ca->slot_count; slot++) { | 997 | for (slot = 0; slot < ca->slot_count; slot++) { |
989 | 998 | ||
999 | mutex_lock(&ca->slot_info[slot].slot_lock); | ||
1000 | |||
990 | // check the cam status + deal with CAMCHANGEs | 1001 | // check the cam status + deal with CAMCHANGEs |
991 | while (dvb_ca_en50221_check_camstatus(ca, slot)) { | 1002 | while (dvb_ca_en50221_check_camstatus(ca, slot)) { |
992 | /* clear down an old CI slot if necessary */ | 1003 | /* clear down an old CI slot if necessary */ |
@@ -1122,7 +1133,7 @@ static int dvb_ca_en50221_thread(void *data) | |||
1122 | 1133 | ||
1123 | case DVB_CA_SLOTSTATE_RUNNING: | 1134 | case DVB_CA_SLOTSTATE_RUNNING: |
1124 | if (!ca->open) | 1135 | if (!ca->open) |
1125 | continue; | 1136 | break; |
1126 | 1137 | ||
1127 | // poll slots for data | 1138 | // poll slots for data |
1128 | pktcount = 0; | 1139 | pktcount = 0; |
@@ -1146,6 +1157,8 @@ static int dvb_ca_en50221_thread(void *data) | |||
1146 | } | 1157 | } |
1147 | break; | 1158 | break; |
1148 | } | 1159 | } |
1160 | |||
1161 | mutex_unlock(&ca->slot_info[slot].slot_lock); | ||
1149 | } | 1162 | } |
1150 | } | 1163 | } |
1151 | 1164 | ||
@@ -1181,6 +1194,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, | |||
1181 | switch (cmd) { | 1194 | switch (cmd) { |
1182 | case CA_RESET: | 1195 | case CA_RESET: |
1183 | for (slot = 0; slot < ca->slot_count; slot++) { | 1196 | for (slot = 0; slot < ca->slot_count; slot++) { |
1197 | mutex_lock(&ca->slot_info[slot].slot_lock); | ||
1184 | if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) { | 1198 | if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) { |
1185 | dvb_ca_en50221_slot_shutdown(ca, slot); | 1199 | dvb_ca_en50221_slot_shutdown(ca, slot); |
1186 | if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) | 1200 | if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) |
@@ -1188,6 +1202,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, | |||
1188 | slot, | 1202 | slot, |
1189 | DVB_CA_EN50221_CAMCHANGE_INSERTED); | 1203 | DVB_CA_EN50221_CAMCHANGE_INSERTED); |
1190 | } | 1204 | } |
1205 | mutex_unlock(&ca->slot_info[slot].slot_lock); | ||
1191 | } | 1206 | } |
1192 | ca->next_read_slot = 0; | 1207 | ca->next_read_slot = 0; |
1193 | dvb_ca_en50221_thread_wakeup(ca); | 1208 | dvb_ca_en50221_thread_wakeup(ca); |
@@ -1308,7 +1323,9 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, | |||
1308 | goto exit; | 1323 | goto exit; |
1309 | } | 1324 | } |
1310 | 1325 | ||
1326 | mutex_lock(&ca->slot_info[slot].slot_lock); | ||
1311 | status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2); | 1327 | status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2); |
1328 | mutex_unlock(&ca->slot_info[slot].slot_lock); | ||
1312 | if (status == (fraglen + 2)) { | 1329 | if (status == (fraglen + 2)) { |
1313 | written = 1; | 1330 | written = 1; |
1314 | break; | 1331 | break; |
@@ -1664,6 +1681,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, | |||
1664 | ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; | 1681 | ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; |
1665 | atomic_set(&ca->slot_info[i].camchange_count, 0); | 1682 | atomic_set(&ca->slot_info[i].camchange_count, 0); |
1666 | ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; | 1683 | ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; |
1684 | mutex_init(&ca->slot_info[i].slot_lock); | ||
1667 | } | 1685 | } |
1668 | 1686 | ||
1669 | if (signal_pending(current)) { | 1687 | if (signal_pending(current)) { |
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.h b/drivers/media/dvb/dvb-core/dvb_ca_en50221.h index 8467e63ddc0d..7df2e141187a 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.h +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.h | |||
@@ -45,8 +45,10 @@ struct dvb_ca_en50221 { | |||
45 | /* the module owning this structure */ | 45 | /* the module owning this structure */ |
46 | struct module* owner; | 46 | struct module* owner; |
47 | 47 | ||
48 | /* NOTE: the read_*, write_* and poll_slot_status functions must use locks as | 48 | /* NOTE: the read_*, write_* and poll_slot_status functions will be |
49 | * they may be called from several threads at once */ | 49 | * called for different slots concurrently and need to use locks where |
50 | * and if appropriate. There will be no concurrent access to one slot. | ||
51 | */ | ||
50 | 52 | ||
51 | /* functions for accessing attribute memory on the CAM */ | 53 | /* functions for accessing attribute memory on the CAM */ |
52 | int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address); | 54 | int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address); |