Commit 81c67b7f authored by Henrik Kurelid's avatar Henrik Kurelid Committed by Stefan Richter

firesat: avc resend

- Add resending of AVC message to the card if no answer is received
  - Replace the homebrewed event_wait function with a standard wait queue
  - Clean up of log/error messages
  - Increase debug level of avc communication
Signed-off-by: default avatarHenrik Kurelid <henrik@kurelid.se>
Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent df4846c3
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
static unsigned int avc_comm_debug = 0; static unsigned int avc_comm_debug = 0;
module_param(avc_comm_debug, int, 0644); module_param(avc_comm_debug, int, 0644);
MODULE_PARM_DESC(avc_comm_debug, "debug logging of AV/C communication, default is 0 (no)"); MODULE_PARM_DESC(avc_comm_debug, "debug logging level [0..2] of AV/C communication, default is 0 (no)");
static int __AVCRegisterRemoteControl(struct firesat*firesat, int internal); static int __AVCRegisterRemoteControl(struct firesat*firesat, int internal);
...@@ -37,22 +37,6 @@ static void avc_free_packet(struct hpsb_packet *packet) ...@@ -37,22 +37,6 @@ static void avc_free_packet(struct hpsb_packet *packet)
hpsb_free_packet(packet); hpsb_free_packet(packet);
} }
/*
* Goofy routine that basically does a down_timeout function.
* Stolen from sbp2.c
*/
static int avc_down_timeout(atomic_t *done, int timeout)
{
int i;
for (i = timeout; (i > 0 && atomic_read(done) == 0); i-= HZ/10) {
set_current_state(TASK_INTERRUPTIBLE);
if (schedule_timeout(HZ/10)) /* 100ms */
return(1);
}
return ((i > 0) ? 0:1);
}
static const char* get_ctype_string(__u8 ctype) static const char* get_ctype_string(__u8 ctype)
{ {
switch(ctype) switch(ctype)
...@@ -135,97 +119,115 @@ static void log_command_frame(const AVCCmdFrm *CmdFrm) ...@@ -135,97 +119,115 @@ static void log_command_frame(const AVCCmdFrm *CmdFrm)
{ {
int k; int k;
printk(KERN_INFO "AV/C Command Frame:\n"); printk(KERN_INFO "AV/C Command Frame:\n");
printk("CommandType=%s, Address=%s(0x%02X,0x%02X), opcode=%s(0x%02X), " printk(KERN_INFO "CommandType=%s, Address=%s(0x%02X,0x%02X), "
"length=%d\n", get_ctype_string(CmdFrm->ctype), "opcode=%s(0x%02X), length=%d\n",
get_ctype_string(CmdFrm->ctype),
get_subunit_address(CmdFrm->suid, CmdFrm->sutyp), get_subunit_address(CmdFrm->suid, CmdFrm->sutyp),
CmdFrm->suid, CmdFrm->sutyp, get_opcode_string(CmdFrm->opcode), CmdFrm->suid, CmdFrm->sutyp, get_opcode_string(CmdFrm->opcode),
CmdFrm->opcode, CmdFrm->length); CmdFrm->opcode, CmdFrm->length);
for(k = 0; k < CmdFrm->length - 3; k++) { if (avc_comm_debug > 1) {
if (k % 5 != 0) for(k = 0; k < CmdFrm->length - 3; k++) {
printk(", "); if (k % 5 != 0)
else if (k != 0) printk(", ");
printk("\n"); else if (k != 0)
printk("operand[%d] = %02X", k, CmdFrm->operand[k]); printk("\n");
printk(KERN_INFO "operand[%d] = %02X", k,
CmdFrm->operand[k]);
}
printk(KERN_INFO "\n");
} }
printk("\n");
} }
static void log_response_frame(const AVCRspFrm *RspFrm) static void log_response_frame(const AVCRspFrm *RspFrm)
{ {
int k; int k;
printk(KERN_INFO "AV/C Response Frame:\n"); printk(KERN_INFO "AV/C Response Frame:\n");
printk("Response=%s, Address=%s(0x%02X,0x%02X), opcode=%s(0x%02X), " printk(KERN_INFO "Response=%s, Address=%s(0x%02X,0x%02X), "
"length=%d\n", get_resp_string(RspFrm->resp), "opcode=%s(0x%02X), length=%d\n", get_resp_string(RspFrm->resp),
get_subunit_address(RspFrm->suid, RspFrm->sutyp), get_subunit_address(RspFrm->suid, RspFrm->sutyp),
RspFrm->suid, RspFrm->sutyp, get_opcode_string(RspFrm->opcode), RspFrm->suid, RspFrm->sutyp, get_opcode_string(RspFrm->opcode),
RspFrm->opcode, RspFrm->length); RspFrm->opcode, RspFrm->length);
for(k = 0; k < RspFrm->length - 3; k++) { if (avc_comm_debug > 1) {
if (k % 5 != 0) for(k = 0; k < RspFrm->length - 3; k++) {
printk(", "); if (k % 5 != 0)
else if (k != 0) printk(KERN_INFO ", ");
printk("\n"); else if (k != 0)
printk("operand[%d] = %02X", k, RspFrm->operand[k]); printk(KERN_INFO "\n");
printk(KERN_INFO "operand[%d] = %02X", k,
RspFrm->operand[k]);
}
printk(KERN_INFO "\n");
} }
printk("\n");
} }
static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm,
AVCRspFrm *RspFrm) { AVCRspFrm *RspFrm) {
struct hpsb_packet *packet; struct hpsb_packet *packet;
struct node_entry *ne; struct node_entry *ne;
int num_tries = 0;
int packet_ok = 0;
ne = firesat->nodeentry; ne = firesat->nodeentry;
if(!ne) { if(!ne) {
printk("%s: lost node!\n",__func__); printk(KERN_ERR "%s: lost node!\n",__func__);
return -EIO; return -EIO;
} }
/* need all input data */ /* need all input data */
if(!firesat || !ne || !CmdFrm) { if(!firesat || !ne || !CmdFrm) {
printk("%s: missing input data!\n",__func__); printk(KERN_ERR "%s: missing input data!\n",__func__);
return -EINVAL; return -EINVAL;
} }
if (avc_comm_debug == 1) { if (avc_comm_debug > 0) {
log_command_frame(CmdFrm); log_command_frame(CmdFrm);
} }
if(RspFrm) if(RspFrm)
atomic_set(&firesat->avc_reply_received, 0); atomic_set(&firesat->avc_reply_received, 0);
packet=hpsb_make_writepacket(ne->host, ne->nodeid, while (packet_ok == 0 && num_tries < 6) {
COMMAND_REGISTER, num_tries++;
(quadlet_t*)CmdFrm, packet_ok = 1;
CmdFrm->length); packet = hpsb_make_writepacket(ne->host, ne->nodeid,
hpsb_set_packet_complete_task(packet, COMMAND_REGISTER,
(void (*)(void*))avc_free_packet, (quadlet_t*)CmdFrm,
packet); CmdFrm->length);
hpsb_node_fill_packet(ne, packet); hpsb_set_packet_complete_task(packet,
(void (*)(void*))avc_free_packet,
if (hpsb_send_packet(packet) < 0) { packet);
avc_free_packet(packet); hpsb_node_fill_packet(ne, packet);
atomic_set(&firesat->avc_reply_received, 1);
printk("%s: send failed!\n",__func__); if (hpsb_send_packet(packet) < 0) {
return -EIO; avc_free_packet(packet);
}
if(RspFrm) {
// AV/C specs say that answers should be send within
// 150 ms so let's time out after 200 ms
if(avc_down_timeout(&firesat->avc_reply_received,
HZ / 5)) {
printk("%s: timeout waiting for avc response\n",
__func__);
atomic_set(&firesat->avc_reply_received, 1); atomic_set(&firesat->avc_reply_received, 1);
return -ETIMEDOUT; printk(KERN_ERR "%s: send failed!\n",__func__);
return -EIO;
} }
memcpy(RspFrm, firesat->respfrm,
firesat->resp_length); if(RspFrm) {
RspFrm->length = firesat->resp_length; // AV/C specs say that answers should be send within
if (avc_comm_debug == 1) { // 150 ms so let's time out after 200 ms
log_response_frame(RspFrm); if (wait_event_timeout(firesat->avc_wait,
atomic_read(&firesat->avc_reply_received) == 1,
HZ / 5) == 0) {
packet_ok = 0;
}
else {
memcpy(RspFrm, firesat->respfrm,
firesat->resp_length);
RspFrm->length = firesat->resp_length;
if (avc_comm_debug > 0) {
log_response_frame(RspFrm);
}
}
} }
} }
if (packet_ok == 0) {
printk(KERN_ERR "%s: AV/C response timed out 6 times.\n",
__func__);
return -ETIMEDOUT;
}
return 0; return 0;
} }
...@@ -292,7 +294,8 @@ int AVCRecv(struct firesat *firesat, u8 *data, size_t length) { ...@@ -292,7 +294,8 @@ int AVCRecv(struct firesat *firesat, u8 *data, size_t length) {
} }
#endif #endif
if(atomic_read(&firesat->avc_reply_received) == 1) { if(atomic_read(&firesat->avc_reply_received) == 1) {
printk("%s: received out-of-order AVC response, ignored\n",__func__); printk(KERN_ERR "%s: received out-of-order AVC response, "
"ignored\n",__func__);
return -EINVAL; return -EINVAL;
} }
// AVCRspFrm *resp=(AVCRspFrm *)data; // AVCRspFrm *resp=(AVCRspFrm *)data;
...@@ -312,6 +315,7 @@ int AVCRecv(struct firesat *firesat, u8 *data, size_t length) { ...@@ -312,6 +315,7 @@ int AVCRecv(struct firesat *firesat, u8 *data, size_t length) {
firesat->resp_length=length; firesat->resp_length=length;
atomic_set(&firesat->avc_reply_received, 1); atomic_set(&firesat->avc_reply_received, 1);
wake_up(&firesat->avc_wait);
return 0; return 0;
} }
...@@ -740,11 +744,12 @@ int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *tr ...@@ -740,11 +744,12 @@ int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *tr
return -EIO; return -EIO;
if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) {
printk("%s: AVCWrite returned error code %d\n",__func__,RspFrm.resp); printk(KERN_ERR "%s: AVCWrite returned error code %d\n",
__func__, RspFrm.resp);
return -EINVAL; return -EINVAL;
} }
if(((RspFrm.operand[3] << 8) + RspFrm.operand[4]) != 8) { if(((RspFrm.operand[3] << 8) + RspFrm.operand[4]) != 8) {
printk("%s: Invalid response length\n",__func__); printk(KERN_ERR "%s: Invalid response length\n", __func__);
return -EINVAL; return -EINVAL;
} }
if(systemId) if(systemId)
...@@ -777,7 +782,8 @@ int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_in ...@@ -777,7 +782,8 @@ int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_in
return -EIO; return -EIO;
if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) {
printk("%s: AVCWrite returned code %d\n",__func__,RspFrm.resp); printk(KERN_ERR "%s: AVCWrite returned code %d\n",
__func__, RspFrm.resp);
return -EINVAL; return -EINVAL;
} }
...@@ -788,7 +794,8 @@ int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_in ...@@ -788,7 +794,8 @@ int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_in
sizeof(ANTENNA_INPUT_INFO)); sizeof(ANTENNA_INPUT_INFO));
return 0; return 0;
} }
printk("%s: invalid info returned from AVC\n",__func__); printk(KERN_ERR "%s: invalid tuner status (op=%d,length=%d) returned "
"from AVC\n", __func__, RspFrm.operand[1], length);
return -EINVAL; return -EINVAL;
} }
...@@ -800,7 +807,8 @@ int AVCLNBControl(struct firesat *firesat, char voltage, char burst, ...@@ -800,7 +807,8 @@ int AVCLNBControl(struct firesat *firesat, char voltage, char burst,
AVCRspFrm RspFrm; AVCRspFrm RspFrm;
int i,j; int i,j;
printk(KERN_INFO "%s: voltage = %x, burst = %x, conttone = %x\n",__func__,voltage,burst,conttone); printk(KERN_INFO "%s: voltage = %x, burst = %x, conttone = %x\n",
__func__, voltage, burst, conttone);
memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); memset(&CmdFrm, 0, sizeof(AVCCmdFrm));
...@@ -822,11 +830,13 @@ int AVCLNBControl(struct firesat *firesat, char voltage, char burst, ...@@ -822,11 +830,13 @@ int AVCLNBControl(struct firesat *firesat, char voltage, char burst,
for(j=0;j<nrdiseq;j++) { for(j=0;j<nrdiseq;j++) {
int k; int k;
printk(KERN_INFO "%s: diseq %d len %x\n",__func__,j,diseqcmd[j].msg_len); printk(KERN_INFO "%s: diseq %d len %x\n",
__func__, j, diseqcmd[j].msg_len);
CmdFrm.operand[i++]=diseqcmd[j].msg_len; CmdFrm.operand[i++]=diseqcmd[j].msg_len;
for(k=0;k<diseqcmd[j].msg_len;k++) { for(k=0;k<diseqcmd[j].msg_len;k++) {
printk(KERN_INFO "%s: diseq %d msg[%d] = %x\n",__func__,j,k,diseqcmd[j].msg[k]); printk(KERN_INFO "%s: diseq %d msg[%d] = %x\n",
__func__, j, k, diseqcmd[j].msg[k]);
CmdFrm.operand[i++]=diseqcmd[j].msg[k]; CmdFrm.operand[i++]=diseqcmd[j].msg[k];
} }
} }
...@@ -847,7 +857,8 @@ int AVCLNBControl(struct firesat *firesat, char voltage, char burst, ...@@ -847,7 +857,8 @@ int AVCLNBControl(struct firesat *firesat, char voltage, char burst,
return -EIO; return -EIO;
if(RspFrm.resp != ACCEPTED) { if(RspFrm.resp != ACCEPTED) {
printk("%s: AVCWrite returned code %d\n",__func__,RspFrm.resp); printk(KERN_ERR "%s: AVCWrite returned code %d\n",
__func__, RspFrm.resp);
return -EINVAL; return -EINVAL;
} }
...@@ -879,7 +890,8 @@ int AVCSubUnitInfo(struct firesat *firesat, char *subunitcount) ...@@ -879,7 +890,8 @@ int AVCSubUnitInfo(struct firesat *firesat, char *subunitcount)
return -EIO; return -EIO;
if(RspFrm.resp != STABLE) { if(RspFrm.resp != STABLE) {
printk("%s: AVCWrite returned code %d\n",__func__,RspFrm.resp); printk(KERN_ERR "%s: AVCWrite returned code %d\n",
__func__, RspFrm.resp);
return -EINVAL; return -EINVAL;
} }
...@@ -1100,9 +1112,10 @@ int avc_ca_pmt(struct firesat *firesat, char *msg, int length) ...@@ -1100,9 +1112,10 @@ int avc_ca_pmt(struct firesat *firesat, char *msg, int length)
CmdFrm.opcode = VENDOR; CmdFrm.opcode = VENDOR;
if (msg[0] != LIST_MANAGEMENT_ONLY) { if (msg[0] != LIST_MANAGEMENT_ONLY) {
printk(KERN_ERR "The only list_manasgement parameter that is " printk(KERN_INFO "%s: list_management %d not support. "
"supported by the firesat driver is \"only\" (3)."); "Forcing list_management to \"only\" (3). \n",
return -EFAULT; __func__, msg[0]);
msg[0] = LIST_MANAGEMENT_ONLY;
} }
// We take the cmd_id from the programme level only! // We take the cmd_id from the programme level only!
list_management = msg[0]; list_management = msg[0];
......
...@@ -140,6 +140,7 @@ struct firesat { ...@@ -140,6 +140,7 @@ struct firesat {
int ca_time_interval; int ca_time_interval;
struct semaphore avc_sem; struct semaphore avc_sem;
wait_queue_head_t avc_wait;
atomic_t avc_reply_received; atomic_t avc_reply_received;
atomic_t reschedule_remotecontrol; atomic_t reschedule_remotecontrol;
......
...@@ -208,6 +208,7 @@ static int firesat_probe(struct device *dev) ...@@ -208,6 +208,7 @@ static int firesat_probe(struct device *dev)
} }
sema_init(&firesat->avc_sem, 1); sema_init(&firesat->avc_sem, 1);
init_waitqueue_head(&firesat->avc_wait);
atomic_set(&firesat->avc_reply_received, 1); atomic_set(&firesat->avc_reply_received, 1);
sema_init(&firesat->demux_sem, 1); sema_init(&firesat->demux_sem, 1);
atomic_set(&firesat->reschedule_remotecontrol, 0); atomic_set(&firesat->reschedule_remotecontrol, 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment