diff options
author | Andy Walls <awalls@md.metrocast.net> | 2011-02-17 18:50:38 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-03-22 18:24:00 -0400 |
commit | d6dbd939b97d271766a58a66d69b27023bc90993 (patch) | |
tree | c5b529b78794bcb823a34bc33489bbb0afecd175 | |
parent | 5bd6b0464b68d429bc8a3fe6595d19c39dfc4d95 (diff) |
[media] lirc_zilog: Add locking of the i2c_clients when in use
Lock the i2c_client pointers and prevent i2c_client removal when
lirc_zilog is perfoming a series of operations that require valid
i2c_client pointers.
Signed-off-by: Andy Walls <awalls@md.metrocast.net>
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/staging/lirc/lirc_zilog.c | 41 |
1 files changed, 37 insertions, 4 deletions
diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 5df90dbba1c6..5946a9541c43 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c | |||
@@ -70,7 +70,7 @@ struct IR_rx { | |||
70 | struct IR *ir; | 70 | struct IR *ir; |
71 | 71 | ||
72 | /* RX device */ | 72 | /* RX device */ |
73 | /* FIXME mutex lock access to this pointer */ | 73 | struct mutex client_lock; |
74 | struct i2c_client *c; | 74 | struct i2c_client *c; |
75 | 75 | ||
76 | /* RX polling thread data */ | 76 | /* RX polling thread data */ |
@@ -86,7 +86,7 @@ struct IR_tx { | |||
86 | struct IR *ir; | 86 | struct IR *ir; |
87 | 87 | ||
88 | /* TX device */ | 88 | /* TX device */ |
89 | /* FIXME mutex lock access to this pointer */ | 89 | struct mutex client_lock; |
90 | struct i2c_client *c; | 90 | struct i2c_client *c; |
91 | 91 | ||
92 | /* TX additional actions needed */ | 92 | /* TX additional actions needed */ |
@@ -341,6 +341,14 @@ static int add_to_buf(struct IR *ir) | |||
341 | if (rx == NULL) | 341 | if (rx == NULL) |
342 | return -ENXIO; | 342 | return -ENXIO; |
343 | 343 | ||
344 | /* Ensure our rx->c i2c_client remains valid for the duration */ | ||
345 | mutex_lock(&rx->client_lock); | ||
346 | if (rx->c == NULL) { | ||
347 | mutex_unlock(&rx->client_lock); | ||
348 | put_ir_rx(rx, false); | ||
349 | return -ENXIO; | ||
350 | } | ||
351 | |||
344 | tx = get_ir_tx(ir); | 352 | tx = get_ir_tx(ir); |
345 | 353 | ||
346 | /* | 354 | /* |
@@ -442,6 +450,7 @@ static int add_to_buf(struct IR *ir) | |||
442 | ret = 0; | 450 | ret = 0; |
443 | } while (!lirc_buffer_full(rbuf)); | 451 | } while (!lirc_buffer_full(rbuf)); |
444 | 452 | ||
453 | mutex_unlock(&rx->client_lock); | ||
445 | if (tx != NULL) | 454 | if (tx != NULL) |
446 | put_ir_tx(tx, false); | 455 | put_ir_tx(tx, false); |
447 | put_ir_rx(rx, false); | 456 | put_ir_rx(rx, false); |
@@ -1089,6 +1098,14 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, | |||
1089 | if (tx == NULL) | 1098 | if (tx == NULL) |
1090 | return -ENXIO; | 1099 | return -ENXIO; |
1091 | 1100 | ||
1101 | /* Ensure our tx->c i2c_client remains valid for the duration */ | ||
1102 | mutex_lock(&tx->client_lock); | ||
1103 | if (tx->c == NULL) { | ||
1104 | mutex_unlock(&tx->client_lock); | ||
1105 | put_ir_tx(tx, false); | ||
1106 | return -ENXIO; | ||
1107 | } | ||
1108 | |||
1092 | /* Lock i2c bus for the duration */ | 1109 | /* Lock i2c bus for the duration */ |
1093 | mutex_lock(&ir->ir_lock); | 1110 | mutex_lock(&ir->ir_lock); |
1094 | 1111 | ||
@@ -1099,6 +1116,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, | |||
1099 | 1116 | ||
1100 | if (copy_from_user(&command, buf + i, sizeof(command))) { | 1117 | if (copy_from_user(&command, buf + i, sizeof(command))) { |
1101 | mutex_unlock(&ir->ir_lock); | 1118 | mutex_unlock(&ir->ir_lock); |
1119 | mutex_unlock(&tx->client_lock); | ||
1102 | put_ir_tx(tx, false); | 1120 | put_ir_tx(tx, false); |
1103 | return -EFAULT; | 1121 | return -EFAULT; |
1104 | } | 1122 | } |
@@ -1109,6 +1127,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, | |||
1109 | ret = fw_load(tx); | 1127 | ret = fw_load(tx); |
1110 | if (ret != 0) { | 1128 | if (ret != 0) { |
1111 | mutex_unlock(&ir->ir_lock); | 1129 | mutex_unlock(&ir->ir_lock); |
1130 | mutex_unlock(&tx->client_lock); | ||
1112 | put_ir_tx(tx, false); | 1131 | put_ir_tx(tx, false); |
1113 | if (ret != -ENOMEM) | 1132 | if (ret != -ENOMEM) |
1114 | ret = -EIO; | 1133 | ret = -EIO; |
@@ -1126,6 +1145,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, | |||
1126 | (unsigned)command & 0xFFFF); | 1145 | (unsigned)command & 0xFFFF); |
1127 | if (ret == -EPROTO) { | 1146 | if (ret == -EPROTO) { |
1128 | mutex_unlock(&ir->ir_lock); | 1147 | mutex_unlock(&ir->ir_lock); |
1148 | mutex_unlock(&tx->client_lock); | ||
1129 | put_ir_tx(tx, false); | 1149 | put_ir_tx(tx, false); |
1130 | return ret; | 1150 | return ret; |
1131 | } | 1151 | } |
@@ -1144,6 +1164,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, | |||
1144 | zilog_error("unable to send to the IR chip " | 1164 | zilog_error("unable to send to the IR chip " |
1145 | "after 3 resets, giving up\n"); | 1165 | "after 3 resets, giving up\n"); |
1146 | mutex_unlock(&ir->ir_lock); | 1166 | mutex_unlock(&ir->ir_lock); |
1167 | mutex_unlock(&tx->client_lock); | ||
1147 | put_ir_tx(tx, false); | 1168 | put_ir_tx(tx, false); |
1148 | return ret; | 1169 | return ret; |
1149 | } | 1170 | } |
@@ -1158,6 +1179,8 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, | |||
1158 | /* Release i2c bus */ | 1179 | /* Release i2c bus */ |
1159 | mutex_unlock(&ir->ir_lock); | 1180 | mutex_unlock(&ir->ir_lock); |
1160 | 1181 | ||
1182 | mutex_unlock(&tx->client_lock); | ||
1183 | |||
1161 | /* Give back our struct IR_tx reference */ | 1184 | /* Give back our struct IR_tx reference */ |
1162 | put_ir_tx(tx, false); | 1185 | put_ir_tx(tx, false); |
1163 | 1186 | ||
@@ -1365,12 +1388,20 @@ static int ir_remove(struct i2c_client *client) | |||
1365 | { | 1388 | { |
1366 | if (strncmp("ir_tx_z8", client->name, 8) == 0) { | 1389 | if (strncmp("ir_tx_z8", client->name, 8) == 0) { |
1367 | struct IR_tx *tx = i2c_get_clientdata(client); | 1390 | struct IR_tx *tx = i2c_get_clientdata(client); |
1368 | if (tx != NULL) | 1391 | if (tx != NULL) { |
1392 | mutex_lock(&tx->client_lock); | ||
1393 | tx->c = NULL; | ||
1394 | mutex_unlock(&tx->client_lock); | ||
1369 | put_ir_tx(tx, false); | 1395 | put_ir_tx(tx, false); |
1396 | } | ||
1370 | } else if (strncmp("ir_rx_z8", client->name, 8) == 0) { | 1397 | } else if (strncmp("ir_rx_z8", client->name, 8) == 0) { |
1371 | struct IR_rx *rx = i2c_get_clientdata(client); | 1398 | struct IR_rx *rx = i2c_get_clientdata(client); |
1372 | if (rx != NULL) | 1399 | if (rx != NULL) { |
1400 | mutex_lock(&rx->client_lock); | ||
1401 | rx->c = NULL; | ||
1402 | mutex_unlock(&rx->client_lock); | ||
1373 | put_ir_rx(rx, false); | 1403 | put_ir_rx(rx, false); |
1404 | } | ||
1374 | } | 1405 | } |
1375 | return 0; | 1406 | return 0; |
1376 | } | 1407 | } |
@@ -1472,6 +1503,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
1472 | ir->tx = tx; | 1503 | ir->tx = tx; |
1473 | 1504 | ||
1474 | ir->l.features |= LIRC_CAN_SEND_PULSE; | 1505 | ir->l.features |= LIRC_CAN_SEND_PULSE; |
1506 | mutex_init(&tx->client_lock); | ||
1475 | tx->c = client; | 1507 | tx->c = client; |
1476 | tx->need_boot = 1; | 1508 | tx->need_boot = 1; |
1477 | tx->post_tx_ready_poll = | 1509 | tx->post_tx_ready_poll = |
@@ -1514,6 +1546,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
1514 | ir->rx = rx; | 1546 | ir->rx = rx; |
1515 | 1547 | ||
1516 | ir->l.features |= LIRC_CAN_REC_LIRCCODE; | 1548 | ir->l.features |= LIRC_CAN_REC_LIRCCODE; |
1549 | mutex_init(&rx->client_lock); | ||
1517 | rx->c = client; | 1550 | rx->c = client; |
1518 | rx->hdpvr_data_fmt = | 1551 | rx->hdpvr_data_fmt = |
1519 | (id->driver_data & ID_FLAG_HDPVR) ? true : false; | 1552 | (id->driver_data & ID_FLAG_HDPVR) ? true : false; |