media: imon_raw: simplify and explain bit operations
authorSean Young <sean@mess.org>
Fri, 9 Aug 2019 21:47:41 +0000 (18:47 -0300)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Wed, 14 Aug 2019 08:05:35 +0000 (05:05 -0300)
This code needs some explanation.

Signed-off-by: Sean Young <sean@mess.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
drivers/media/rc/imon_raw.c

index 25e56c5..e672399 100644 (file)
@@ -14,7 +14,7 @@ struct imon {
        struct device *dev;
        struct urb *ir_urb;
        struct rc_dev *rcdev;
-       u8 ir_buf[8] __aligned(__alignof__(u64));
+       __be64 ir_buf;
        char phys[64];
 };
 
@@ -29,14 +29,35 @@ struct imon {
 static void imon_ir_data(struct imon *imon)
 {
        struct ir_raw_event rawir = {};
-       u64 d = be64_to_cpup((__be64 *)imon->ir_buf) >> 24;
+       u64 data = be64_to_cpu(imon->ir_buf);
+       u8 packet_no = data & 0xff;
        int offset = 40;
        int bit;
 
-       dev_dbg(imon->dev, "data: %*ph", 8, imon->ir_buf);
+       if (packet_no == 0xff)
+               return;
+
+       dev_dbg(imon->dev, "data: %*ph", 8, &imon->ir_buf);
+
+       /*
+        * Only the first 5 bytes contain IR data. Right shift so we move
+        * the IR bits to the lower 40 bits.
+        */
+       data >>= 24;
 
        do {
-               bit = fls64(d & (BIT_ULL(offset) - 1));
+               /*
+                * Find highest set bit which is less or equal to offset
+                *
+                * offset is the bit above (base 0) where we start looking.
+                *
+                * data & (BIT_ULL(offset) - 1) masks off any unwanted bits,
+                * so we have just bits less than offset.
+                *
+                * fls will tell us the highest bit set plus 1 (or 0 if no
+                * bits are set).
+                */
+               bit = fls64(data & (BIT_ULL(offset) - 1));
                if (bit < offset) {
                        dev_dbg(imon->dev, "pulse: %d bits", offset - bit);
                        rawir.pulse = true;
@@ -49,7 +70,12 @@ static void imon_ir_data(struct imon *imon)
                        offset = bit;
                }
 
-               bit = fls64(~d & (BIT_ULL(offset) - 1));
+               /*
+                * Find highest clear bit which is less than offset.
+                *
+                * Just invert the data and use same trick as above.
+                */
+               bit = fls64(~data & (BIT_ULL(offset) - 1));
                dev_dbg(imon->dev, "space: %d bits", offset - bit);
 
                rawir.pulse = false;
@@ -59,7 +85,7 @@ static void imon_ir_data(struct imon *imon)
                offset = bit;
        } while (offset > 0);
 
-       if (imon->ir_buf[7] == 0x0a) {
+       if (packet_no == 0x0a) {
                ir_raw_event_set_idle(imon->rcdev, true);
                ir_raw_event_handle(imon->rcdev);
        }
@@ -72,8 +98,7 @@ static void imon_ir_rx(struct urb *urb)
 
        switch (urb->status) {
        case 0:
-               if (imon->ir_buf[7] != 0xff)
-                       imon_ir_data(imon);
+               imon_ir_data(imon);
                break;
        case -ECONNRESET:
        case -ENOENT:
@@ -129,7 +154,7 @@ static int imon_probe(struct usb_interface *intf,
        imon->dev = &intf->dev;
        usb_fill_int_urb(imon->ir_urb, udev,
                         usb_rcvintpipe(udev, ir_ep->bEndpointAddress),
-                        imon->ir_buf, sizeof(imon->ir_buf),
+                        &imon->ir_buf, sizeof(imon->ir_buf),
                         imon_ir_rx, imon, ir_ep->bInterval);
 
        rcdev = devm_rc_allocate_device(&intf->dev, RC_DRIVER_IR_RAW);