summaryrefslogtreecommitdiff
path: root/drivers/media/dvb/firesat/cmp.c
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2008-11-02 12:45:00 (GMT)
committerStefan Richter <stefanr@s5r6.in-berlin.de>2009-02-24 13:51:28 (GMT)
commit8ae83cdf3297d7da301af36bdb6ff45bd331c6d0 (patch)
tree0363a01f1b3655507bdaf7e1f55af6a3ee9d26b7 /drivers/media/dvb/firesat/cmp.c
parent00fc3072e484c1c6fdbd9c3b1851f866000a6cb9 (diff)
downloadlinux-fsl-qoriq-8ae83cdf3297d7da301af36bdb6ff45bd331c6d0.tar.xz
firedtv: cleanups and minor fixes
Combination of the following changes: Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: increase FCP frame length for DVB-S2 tune QSPK The last three bytes didn't go out to the wire. Effect of the fix not yet tested. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: replace mdelay by msleep These functions can sleep (and in fact sleep for the duration of a whole FCP transaction). Hence msleep is more appropriate here. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: trivial reorganization in avc_api Reduce nesting level by factoring code out of avc_tuner_dsd() into helper functions. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: trivial cleanups in avc_api Use dev_err(), no CamelCase function names, adjust comment style, put #if 0 around unused code and add FIXME comments, standardize on lower-case hexadecimal constants, use ALIGN() for some frame length calculations, make a local function static... The code which writes FCP command frames and reads FCP response frames is not yet brought into canonical kernel coding style because this involves changes of typedefs (on-the-wire bitfields). Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: don't retry oPCR updates endlessly In the theoretical case that the target node wasn't handling the lock transactions as expected or there was continued interference by other initiating nodes, these functions wouldn't return for ages. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: remove bitfield typedefs from cmp, fix for big endian CPUs Use macros/ inline functions/ standard byte order accessors to read and write oPCR register values (big endian bitfields, on-the-wire data). The new code may not be the ultimate optimum, but it doesn't occur in a hot path. This fixes the CMP code for big endian CPUs. So far I tested it only on a little endian CPU though. For now, include <asm/byteorder.h> instead of <linux/byteorder.h> because drivers/ieee1394/*.h also include the former. I will fix this in drivers/ieee1394 and firedtv later. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: trivial cleanups in cmp Reduce nesting level by means of early exit and goto. Remove obsolete includes, use dev_err(), no CamelCase function names... Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: trivial cleanups in firesat-ci Whitespace, variable names, comment style... Also, use dvb_generic_open() and dvb_generic_release() directly as our hooks in struct file_operations because firedtv's wrappers merely called these generic functions. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: remove CA debug code This looks like it is not necessary to have available for endusers who cannot patch kernels for bug reporting and tests of fixes. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: remove AV/C debug code This looks like it is not necessary to have available for endusers who cannot patch kernels for bug reporting and tests of fixes. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: remove various debug code Most of this was already commented out. And that which wasn't is not relevant in normal use. Mon, 29 Sep 2008 19:22:48 +0200 (CEST) firedtv: register input device as child of a FireWire device Instead of one virtual input device which exists for the whole lifetime of the driver and receives events from all connected FireDTVs, register one input device for each firedtv device. These input devices will show up as children of the respective firedtv devices in the sysfs hierarchy. However, the implementation falls short because of a bug in userspace: Udev's path_id script gets stuck with 100% CPU utilization, maybe because of an assumption about the maximum ieee1394 device hierarchy depth. To avoid this bug, we use the fw-host device instead of the proper unit_directory device as parent of the input device. There is hope that the port to the new firewire stack won't be inhibited by this userspace bug because there are no fw-host devices there. Mon, 29 Sep 2008 19:21:52 +0200 (CEST) firedtv: fix string comparison and a few sparse warnings Sparse found a bug: while ((kv_buf + kv_len - 1) == '\0') should have been while (kv_buf[kv_len - 1] == '\0') We fix it by a better implementation without a temporary copy. Also fix sparse warnings of 0 instead of NULL and signedness mismatches. Mon, 29 Sep 2008 19:21:20 +0200 (CEST) firedtv: remove unused struct members and redefine an int as a bool. Mon, 29 Sep 2008 19:20:36 +0200 (CEST) firedtv: fix initialization of dvb_frontend.ops There was a NULL pointer reference if no dvb_frontend_info was found. Also, don't directly assign struct typed values to struct typed variables. Instead write out assignments to individual strcut members. This reduces module size by about 1 kB. Mon, 29 Sep 2008 19:19:41 +0200 (CEST) firedtv: remove unused dual subunit code from initialization No FireDTVs with more than one subunit exists, hence simplify the initialization for the special case of one subunit. The driver was able to check for more than one subunit but was broken for more than two subunits. While we are at it, add several missing cleanups after failure, and include a few dynamically allocated structures diretly into struct firesat instead of allocating them separately. Mon, 29 Sep 2008 19:19:08 +0200 (CEST) firedtv: add vendor_id and version to driver match table Now that nodemgr was enhanced to match against the root directory's vendor ID if there isn't one in the unit directory, use this to prevent firedtv to be bound to wrong devices by accident. Also add the AV/C software version ID to the match flags for completeness; specifier ID and software only make sense as a pair. Mon, 29 Sep 2008 19:18:30 +0200 (CEST) firedtv: use hpsb_node_read(), _write(), _lock() because they are simpler and treat the node generation more correctly. While we are at it, clean up and simplify surrounding code. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/media/dvb/firesat/cmp.c')
-rw-r--r--drivers/media/dvb/firesat/cmp.c252
1 files changed, 112 insertions, 140 deletions
diff --git a/drivers/media/dvb/firesat/cmp.c b/drivers/media/dvb/firesat/cmp.c
index d1bafba..8e98b81 100644
--- a/drivers/media/dvb/firesat/cmp.c
+++ b/drivers/media/dvb/firesat/cmp.c
@@ -10,37 +10,21 @@
* the License, or (at your option) any later version.
*/
+#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/types.h>
-#include <hosts.h>
+#include <asm/byteorder.h>
+
#include <ieee1394.h>
-#include <ieee1394_core.h>
-#include <ieee1394_transactions.h>
#include <nodemgr.h>
#include "avc_api.h"
#include "cmp.h"
#include "firesat.h"
-typedef struct _OPCR
-{
- __u8 PTPConnCount : 6 ; // Point to point connect. counter
- __u8 BrConnCount : 1 ; // Broadcast connection counter
- __u8 OnLine : 1 ; // On Line
-
- __u8 ChNr : 6 ; // Channel number
- __u8 Res : 2 ; // Reserved
-
- __u8 PayloadHi : 2 ; // Payoad high bits
- __u8 OvhdID : 4 ; // Overhead ID
- __u8 DataRate : 2 ; // Data Rate
-
- __u8 PayloadLo ; // Payoad low byte
-} OPCR ;
-
-#define FIRESAT_SPEED IEEE1394_SPEED_400
+#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL
static int cmp_read(struct firesat *firesat, void *buf, u64 addr, size_t len)
{
@@ -49,151 +33,139 @@ static int cmp_read(struct firesat *firesat, void *buf, u64 addr, size_t len)
if (mutex_lock_interruptible(&firesat->avc_mutex))
return -EINTR;
- ret = hpsb_read(firesat->host, firesat->nodeentry->nodeid,
- firesat->nodeentry->generation, addr, buf, len);
+ ret = hpsb_node_read(firesat->ud->ne, addr, buf, len);
+ if (ret < 0)
+ dev_err(&firesat->ud->device, "CMP: read I/O error\n");
mutex_unlock(&firesat->avc_mutex);
return ret;
}
-static int cmp_lock(struct firesat *firesat, quadlet_t *data, u64 addr,
- quadlet_t arg, int ext_tcode)
+static int cmp_lock(struct firesat *firesat, void *data, u64 addr, __be32 arg,
+ int ext_tcode)
{
int ret;
if (mutex_lock_interruptible(&firesat->avc_mutex))
return -EINTR;
- ret = hpsb_lock(firesat->host, firesat->nodeentry->nodeid,
- firesat->nodeentry->generation,
- addr, ext_tcode, data, arg);
+ ret = hpsb_node_lock(firesat->ud->ne, addr, ext_tcode, data,
+ (__force quadlet_t)arg);
+ if (ret < 0)
+ dev_err(&firesat->ud->device, "CMP: lock I/O error\n");
mutex_unlock(&firesat->avc_mutex);
return ret;
}
-//try establishing a point-to-point connection (may be interrupted by a busreset
-int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int iso_channel) {
- unsigned int BWU; //bandwidth to allocate
+static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift)
+{
+ return (be32_to_cpu(opcr) >> shift) & mask;
+}
+
+static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift)
+{
+ *opcr &= ~cpu_to_be32(mask << shift);
+ *opcr |= cpu_to_be32((value & mask) << shift);
+}
- quadlet_t old_oPCR,test_oPCR = 0x0;
- u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
- int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
+#define get_opcr_online(v) get_opcr((v), 0x1, 31)
+#define get_opcr_p2p_connections(v) get_opcr((v), 0x3f, 24)
+#define get_opcr_channel(v) get_opcr((v), 0x3f, 16)
-/* printk(KERN_INFO "%s: nodeid = %d\n",__func__,firesat->nodeentry->nodeid); */
+#define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24)
+#define set_opcr_channel(p, v) set_opcr((p), (v), 0x3f, 16)
+#define set_opcr_data_rate(p, v) set_opcr((p), (v), 0x3, 14)
+#define set_opcr_overhead_id(p, v) set_opcr((p), (v), 0xf, 10)
- if (result < 0) {
- printk("%s: cannot read oPCR\n", __func__);
- return result;
- } else {
-/* printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR); */
- do {
- OPCR *hilf= (OPCR*) &test_oPCR;
-
- if (!hilf->OnLine) {
- printk("%s: Output offline; oPCR: %08x\n", __func__, test_oPCR);
- return -EBUSY;
- } else {
- quadlet_t new_oPCR;
-
- old_oPCR=test_oPCR;
- if (hilf->PTPConnCount) {
- if (hilf->ChNr != iso_channel) {
- printk("%s: Output plug has already connection on channel %u; cannot change it to channel %u\n",__func__,hilf->ChNr,iso_channel);
- return -EBUSY;
- } else
- printk(KERN_INFO "%s: Overlaying existing connection; connection counter was: %u\n",__func__, hilf->PTPConnCount);
- BWU=0; //we allocate no bandwidth (is this necessary?)
- } else {
- hilf->ChNr=iso_channel;
- hilf->DataRate=FIRESAT_SPEED;
-
- hilf->OvhdID=0; //FIXME: that is for worst case -> optimize
- BWU=hilf->OvhdID?hilf->OvhdID*32:512;
- BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
-/* if (allocate_1394_resources(iso_channel,BWU))
- {
- cout << "Allocation of resources failed\n";
- return -2;
- }*/
- }
-
- hilf->PTPConnCount++;
- new_oPCR=test_oPCR;
-/* printk(KERN_INFO "%s: trying compare_swap...\n",__func__); */
-/* printk(KERN_INFO "%s: oPCR_old: %08x, oPCR_new: %08x\n",__func__, old_oPCR, new_oPCR); */
- result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
-
- if (result < 0) {
- printk("%s: cannot compare_swap oPCR\n",__func__);
- return result;
- }
- if ((old_oPCR != test_oPCR) && (!((OPCR*) &old_oPCR)->PTPConnCount))
- {
- printk("%s: change of oPCR failed -> freeing resources\n",__func__);
-// hilf= (OPCR*) &new_oPCR;
-// unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
-// BWU += (hilf->Payload+3) * (2 << (3-hilf->DataRate));
-/* if (deallocate_1394_resources(iso_channel,BWU))
- {
-
- cout << "Deallocation of resources failed\n";
- return -3;
- }*/
- }
- }
+int cmp_establish_pp_connection(struct firesat *firesat, int plug, int channel)
+{
+ __be32 old_opcr, opcr;
+ u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
+ int attempts = 0;
+ int ret;
+
+ ret = cmp_read(firesat, &opcr, opcr_address, 4);
+ if (ret < 0)
+ return ret;
+
+repeat:
+ if (!get_opcr_online(opcr)) {
+ dev_err(&firesat->ud->device, "CMP: output offline\n");
+ return -EBUSY;
+ }
+
+ old_opcr = opcr;
+
+ if (get_opcr_p2p_connections(opcr)) {
+ if (get_opcr_channel(opcr) != channel) {
+ dev_err(&firesat->ud->device,
+ "CMP: cannot change channel\n");
+ return -EBUSY;
}
- while (old_oPCR != test_oPCR);
+ dev_info(&firesat->ud->device,
+ "CMP: overlaying existing connection\n");
+
+ /* We don't allocate isochronous resources. */
+ } else {
+ set_opcr_channel(&opcr, channel);
+ set_opcr_data_rate(&opcr, IEEE1394_SPEED_400);
+
+ /* FIXME: this is for the worst case - optimize */
+ set_opcr_overhead_id(&opcr, 0);
+
+ /* FIXME: allocate isochronous channel and bandwidth at IRM */
}
+
+ set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) + 1);
+
+ ret = cmp_lock(firesat, &opcr, opcr_address, old_opcr, 2);
+ if (ret < 0)
+ return ret;
+
+ if (old_opcr != opcr) {
+ /*
+ * FIXME: if old_opcr.P2P_Connections > 0,
+ * deallocate isochronous channel and bandwidth at IRM
+ */
+
+ if (++attempts < 6) /* arbitrary limit */
+ goto repeat;
+ return -EBUSY;
+ }
+
return 0;
}
-//try breaking a point-to-point connection (may be interrupted by a busreset
-int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_channel) {
- quadlet_t old_oPCR,test_oPCR;
+void cmp_break_pp_connection(struct firesat *firesat, int plug, int channel)
+{
+ __be32 old_opcr, opcr;
+ u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
+ int attempts = 0;
+
+ if (cmp_read(firesat, &opcr, opcr_address, 4) < 0)
+ return;
+
+repeat:
+ if (!get_opcr_online(opcr) || !get_opcr_p2p_connections(opcr) ||
+ get_opcr_channel(opcr) != channel) {
+ dev_err(&firesat->ud->device, "CMP: no connection to break\n");
+ return;
+ }
+
+ old_opcr = opcr;
+ set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) - 1);
- u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
- int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
+ if (cmp_lock(firesat, &opcr, opcr_address, old_opcr, 2) < 0)
+ return;
-/* printk(KERN_INFO "%s\n",__func__); */
+ if (old_opcr != opcr) {
+ /*
+ * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last
+ * owner, deallocate isochronous channel and bandwidth at IRM
+ */
- if (result < 0) {
- printk("%s: cannot read oPCR\n", __func__);
- return result;
- } else {
- do {
- OPCR *hilf= (OPCR*) &test_oPCR;
-
- if (!hilf->OnLine || !hilf->PTPConnCount || hilf->ChNr != iso_channel) {
- printk("%s: Output plug does not have PtP-connection on that channel; oPCR: %08x\n", __func__, test_oPCR);
- return -EINVAL;
- } else {
- quadlet_t new_oPCR;
- old_oPCR=test_oPCR;
- hilf->PTPConnCount--;
- new_oPCR=test_oPCR;
-
-// printk(KERN_INFO "%s: trying compare_swap...\n", __func__);
- result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
- if (result < 0) {
- printk("%s: cannot compare_swap oPCR\n",__func__);
- return result;
- }
- }
-
- } while (old_oPCR != test_oPCR);
-
-/* hilf = (OPCR*) &old_oPCR;
- if (hilf->PTPConnCount == 1) { // if we were the last owner of this connection
- cout << "deallocating 1394 resources\n";
- unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
- BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
- if (deallocate_1394_resources(iso_channel,BWU))
- {
- cout << "Deallocation of resources failed\n";
- return -3;
- }
- }*/
- }
- return 0;
+ if (++attempts < 6) /* arbitrary limit */
+ goto repeat;
+ }
}