LCOV - code coverage report
Current view: top level - drivers/input/mouse - byd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 117 0.0 %
Date: 2023-03-27 20:00:47 Functions: 0 8 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-only
       2             : /*
       3             :  * BYD TouchPad PS/2 mouse driver
       4             :  *
       5             :  * Copyright (C) 2015 Chris Diamand <chris@diamand.org>
       6             :  * Copyright (C) 2015 Richard Pospesel
       7             :  * Copyright (C) 2015 Tai Chi Minh Ralph Eastwood
       8             :  * Copyright (C) 2015 Martin Wimpress
       9             :  * Copyright (C) 2015 Jay Kuri
      10             :  */
      11             : 
      12             : #include <linux/delay.h>
      13             : #include <linux/input.h>
      14             : #include <linux/libps2.h>
      15             : #include <linux/serio.h>
      16             : #include <linux/slab.h>
      17             : 
      18             : #include "psmouse.h"
      19             : #include "byd.h"
      20             : 
      21             : /* PS2 Bits */
      22             : #define PS2_Y_OVERFLOW  BIT_MASK(7)
      23             : #define PS2_X_OVERFLOW  BIT_MASK(6)
      24             : #define PS2_Y_SIGN      BIT_MASK(5)
      25             : #define PS2_X_SIGN      BIT_MASK(4)
      26             : #define PS2_ALWAYS_1    BIT_MASK(3)
      27             : #define PS2_MIDDLE      BIT_MASK(2)
      28             : #define PS2_RIGHT       BIT_MASK(1)
      29             : #define PS2_LEFT        BIT_MASK(0)
      30             : 
      31             : /*
      32             :  * BYD pad constants
      33             :  */
      34             : 
      35             : /*
      36             :  * True device resolution is unknown, however experiments show the
      37             :  * resolution is about 111 units/mm.
      38             :  * Absolute coordinate packets are in the range 0-255 for both X and Y
      39             :  * we pick ABS_X/ABS_Y dimensions which are multiples of 256 and in
      40             :  * the right ballpark given the touchpad's physical dimensions and estimate
      41             :  * resolution per spec sheet, device active area dimensions are
      42             :  * 101.6 x 60.1 mm.
      43             :  */
      44             : #define BYD_PAD_WIDTH           11264
      45             : #define BYD_PAD_HEIGHT          6656
      46             : #define BYD_PAD_RESOLUTION      111
      47             : 
      48             : /*
      49             :  * Given the above dimensions, relative packets velocity is in multiples of
      50             :  * 1 unit / 11 milliseconds.  We use this dt to estimate distance traveled
      51             :  */
      52             : #define BYD_DT                  11
      53             : /* Time in jiffies used to timeout various touch events (64 ms) */
      54             : #define BYD_TOUCH_TIMEOUT       msecs_to_jiffies(64)
      55             : 
      56             : /* BYD commands reverse engineered from windows driver */
      57             : 
      58             : /*
      59             :  * Swipe gesture from off-pad to on-pad
      60             :  *  0 : disable
      61             :  *  1 : enable
      62             :  */
      63             : #define BYD_CMD_SET_OFFSCREEN_SWIPE             0x10cc
      64             : /*
      65             :  * Tap and drag delay time
      66             :  *  0 : disable
      67             :  *  1 - 8 : least to most delay
      68             :  */
      69             : #define BYD_CMD_SET_TAP_DRAG_DELAY_TIME         0x10cf
      70             : /*
      71             :  * Physical buttons function mapping
      72             :  *  0 : enable
      73             :  *  4 : normal
      74             :  *  5 : left button custom command
      75             :  *  6 : right button custom command
      76             :  *  8 : disable
      77             :  */
      78             : #define BYD_CMD_SET_PHYSICAL_BUTTONS            0x10d0
      79             : /*
      80             :  * Absolute mode (1 byte X/Y resolution)
      81             :  *  0 : disable
      82             :  *  2 : enable
      83             :  */
      84             : #define BYD_CMD_SET_ABSOLUTE_MODE               0x10d1
      85             : /*
      86             :  * Two finger scrolling
      87             :  *  1 : vertical
      88             :  *  2 : horizontal
      89             :  *  3 : vertical + horizontal
      90             :  *  4 : disable
      91             :  */
      92             : #define BYD_CMD_SET_TWO_FINGER_SCROLL           0x10d2
      93             : /*
      94             :  * Handedness
      95             :  *  1 : right handed
      96             :  *  2 : left handed
      97             :  */
      98             : #define BYD_CMD_SET_HANDEDNESS                  0x10d3
      99             : /*
     100             :  * Tap to click
     101             :  *  1 : enable
     102             :  *  2 : disable
     103             :  */
     104             : #define BYD_CMD_SET_TAP                         0x10d4
     105             : /*
     106             :  * Tap and drag
     107             :  *  1 : tap and hold to drag
     108             :  *  2 : tap and hold to drag + lock
     109             :  *  3 : disable
     110             :  */
     111             : #define BYD_CMD_SET_TAP_DRAG                    0x10d5
     112             : /*
     113             :  * Touch sensitivity
     114             :  *  1 - 7 : least to most sensitive
     115             :  */
     116             : #define BYD_CMD_SET_TOUCH_SENSITIVITY           0x10d6
     117             : /*
     118             :  * One finger scrolling
     119             :  *  1 : vertical
     120             :  *  2 : horizontal
     121             :  *  3 : vertical + horizontal
     122             :  *  4 : disable
     123             :  */
     124             : #define BYD_CMD_SET_ONE_FINGER_SCROLL           0x10d7
     125             : /*
     126             :  * One finger scrolling function
     127             :  *  1 : free scrolling
     128             :  *  2 : edge motion
     129             :  *  3 : free scrolling + edge motion
     130             :  *  4 : disable
     131             :  */
     132             : #define BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC      0x10d8
     133             : /*
     134             :  * Sliding speed
     135             :  *  1 - 5 : slowest to fastest
     136             :  */
     137             : #define BYD_CMD_SET_SLIDING_SPEED               0x10da
     138             : /*
     139             :  * Edge motion
     140             :  *  1 : disable
     141             :  *  2 : enable when dragging
     142             :  *  3 : enable when dragging and pointing
     143             :  */
     144             : #define BYD_CMD_SET_EDGE_MOTION                 0x10db
     145             : /*
     146             :  * Left edge region size
     147             :  *  0 - 7 : smallest to largest width
     148             :  */
     149             : #define BYD_CMD_SET_LEFT_EDGE_REGION            0x10dc
     150             : /*
     151             :  * Top edge region size
     152             :  *  0 - 9 : smallest to largest height
     153             :  */
     154             : #define BYD_CMD_SET_TOP_EDGE_REGION             0x10dd
     155             : /*
     156             :  * Disregard palm press as clicks
     157             :  *  1 - 6 : smallest to largest
     158             :  */
     159             : #define BYD_CMD_SET_PALM_CHECK                  0x10de
     160             : /*
     161             :  * Right edge region size
     162             :  *  0 - 7 : smallest to largest width
     163             :  */
     164             : #define BYD_CMD_SET_RIGHT_EDGE_REGION           0x10df
     165             : /*
     166             :  * Bottom edge region size
     167             :  *  0 - 9 : smallest to largest height
     168             :  */
     169             : #define BYD_CMD_SET_BOTTOM_EDGE_REGION          0x10e1
     170             : /*
     171             :  * Multitouch gestures
     172             :  *  1 : enable
     173             :  *  2 : disable
     174             :  */
     175             : #define BYD_CMD_SET_MULTITOUCH                  0x10e3
     176             : /*
     177             :  * Edge motion speed
     178             :  *  0 : control with finger pressure
     179             :  *  1 - 9 : slowest to fastest
     180             :  */
     181             : #define BYD_CMD_SET_EDGE_MOTION_SPEED           0x10e4
     182             : /*
     183             :  * Two finger scolling function
     184             :  *  0 : free scrolling
     185             :  *  1 : free scrolling (with momentum)
     186             :  *  2 : edge motion
     187             :  *  3 : free scrolling (with momentum) + edge motion
     188             :  *  4 : disable
     189             :  */
     190             : #define BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC      0x10e5
     191             : 
     192             : /*
     193             :  * The touchpad generates a mixture of absolute and relative packets, indicated
     194             :  * by the last byte of each packet being set to one of the following:
     195             :  */
     196             : #define BYD_PACKET_ABSOLUTE                     0xf8
     197             : #define BYD_PACKET_RELATIVE                     0x00
     198             : /* Multitouch gesture packets */
     199             : #define BYD_PACKET_PINCH_IN                     0xd8
     200             : #define BYD_PACKET_PINCH_OUT                    0x28
     201             : #define BYD_PACKET_ROTATE_CLOCKWISE             0x29
     202             : #define BYD_PACKET_ROTATE_ANTICLOCKWISE         0xd7
     203             : #define BYD_PACKET_TWO_FINGER_SCROLL_RIGHT      0x2a
     204             : #define BYD_PACKET_TWO_FINGER_SCROLL_DOWN       0x2b
     205             : #define BYD_PACKET_TWO_FINGER_SCROLL_UP         0xd5
     206             : #define BYD_PACKET_TWO_FINGER_SCROLL_LEFT       0xd6
     207             : #define BYD_PACKET_THREE_FINGER_SWIPE_RIGHT     0x2c
     208             : #define BYD_PACKET_THREE_FINGER_SWIPE_DOWN      0x2d
     209             : #define BYD_PACKET_THREE_FINGER_SWIPE_UP        0xd3
     210             : #define BYD_PACKET_THREE_FINGER_SWIPE_LEFT      0xd4
     211             : #define BYD_PACKET_FOUR_FINGER_DOWN             0x33
     212             : #define BYD_PACKET_FOUR_FINGER_UP               0xcd
     213             : #define BYD_PACKET_REGION_SCROLL_RIGHT          0x35
     214             : #define BYD_PACKET_REGION_SCROLL_DOWN           0x36
     215             : #define BYD_PACKET_REGION_SCROLL_UP             0xca
     216             : #define BYD_PACKET_REGION_SCROLL_LEFT           0xcb
     217             : #define BYD_PACKET_RIGHT_CORNER_CLICK           0xd2
     218             : #define BYD_PACKET_LEFT_CORNER_CLICK            0x2e
     219             : #define BYD_PACKET_LEFT_AND_RIGHT_CORNER_CLICK  0x2f
     220             : #define BYD_PACKET_ONTO_PAD_SWIPE_RIGHT         0x37
     221             : #define BYD_PACKET_ONTO_PAD_SWIPE_DOWN          0x30
     222             : #define BYD_PACKET_ONTO_PAD_SWIPE_UP            0xd0
     223             : #define BYD_PACKET_ONTO_PAD_SWIPE_LEFT          0xc9
     224             : 
     225             : struct byd_data {
     226             :         struct timer_list timer;
     227             :         struct psmouse *psmouse;
     228             :         s32 abs_x;
     229             :         s32 abs_y;
     230             :         typeof(jiffies) last_touch_time;
     231             :         bool btn_left;
     232             :         bool btn_right;
     233             :         bool touch;
     234             : };
     235             : 
     236           0 : static void byd_report_input(struct psmouse *psmouse)
     237             : {
     238           0 :         struct byd_data *priv = psmouse->private;
     239           0 :         struct input_dev *dev = psmouse->dev;
     240             : 
     241           0 :         input_report_key(dev, BTN_TOUCH, priv->touch);
     242           0 :         input_report_key(dev, BTN_TOOL_FINGER, priv->touch);
     243             : 
     244           0 :         input_report_abs(dev, ABS_X, priv->abs_x);
     245           0 :         input_report_abs(dev, ABS_Y, priv->abs_y);
     246           0 :         input_report_key(dev, BTN_LEFT, priv->btn_left);
     247           0 :         input_report_key(dev, BTN_RIGHT, priv->btn_right);
     248             : 
     249           0 :         input_sync(dev);
     250           0 : }
     251             : 
     252           0 : static void byd_clear_touch(struct timer_list *t)
     253             : {
     254           0 :         struct byd_data *priv = from_timer(priv, t, timer);
     255           0 :         struct psmouse *psmouse = priv->psmouse;
     256             : 
     257           0 :         serio_pause_rx(psmouse->ps2dev.serio);
     258           0 :         priv->touch = false;
     259             : 
     260           0 :         byd_report_input(psmouse);
     261             : 
     262           0 :         serio_continue_rx(psmouse->ps2dev.serio);
     263             : 
     264             :         /*
     265             :          * Move cursor back to center of pad when we lose touch - this
     266             :          * specifically improves user experience when moving cursor with one
     267             :          * finger, and pressing a button with another.
     268             :          */
     269           0 :         priv->abs_x = BYD_PAD_WIDTH / 2;
     270           0 :         priv->abs_y = BYD_PAD_HEIGHT / 2;
     271           0 : }
     272             : 
     273           0 : static psmouse_ret_t byd_process_byte(struct psmouse *psmouse)
     274             : {
     275           0 :         struct byd_data *priv = psmouse->private;
     276           0 :         u8 *pkt = psmouse->packet;
     277             : 
     278           0 :         if (psmouse->pktcnt > 0 && !(pkt[0] & PS2_ALWAYS_1)) {
     279           0 :                 psmouse_warn(psmouse, "Always_1 bit not 1. pkt[0] = %02x\n",
     280             :                              pkt[0]);
     281           0 :                 return PSMOUSE_BAD_DATA;
     282             :         }
     283             : 
     284           0 :         if (psmouse->pktcnt < psmouse->pktsize)
     285             :                 return PSMOUSE_GOOD_DATA;
     286             : 
     287             :         /* Otherwise, a full packet has been received */
     288           0 :         switch (pkt[3]) {
     289             :         case BYD_PACKET_ABSOLUTE:
     290             :                 /* Only use absolute packets for the start of movement. */
     291           0 :                 if (!priv->touch) {
     292             :                         /* needed to detect tap */
     293           0 :                         typeof(jiffies) tap_time =
     294           0 :                                 priv->last_touch_time + BYD_TOUCH_TIMEOUT;
     295           0 :                         priv->touch = time_after(jiffies, tap_time);
     296             : 
     297             :                         /* init abs position */
     298           0 :                         priv->abs_x = pkt[1] * (BYD_PAD_WIDTH / 256);
     299           0 :                         priv->abs_y = (255 - pkt[2]) * (BYD_PAD_HEIGHT / 256);
     300             :                 }
     301             :                 break;
     302             :         case BYD_PACKET_RELATIVE: {
     303             :                 /* Standard packet */
     304             :                 /* Sign-extend if a sign bit is set. */
     305           0 :                 u32 signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0;
     306           0 :                 u32 signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0;
     307           0 :                 s32 dx = signx | (int) pkt[1];
     308           0 :                 s32 dy = signy | (int) pkt[2];
     309             : 
     310             :                 /* Update position based on velocity */
     311           0 :                 priv->abs_x += dx * BYD_DT;
     312           0 :                 priv->abs_y -= dy * BYD_DT;
     313             : 
     314           0 :                 priv->touch = true;
     315           0 :                 break;
     316             :         }
     317             :         default:
     318           0 :                 psmouse_warn(psmouse,
     319             :                              "Unrecognized Z: pkt = %02x %02x %02x %02x\n",
     320             :                              psmouse->packet[0], psmouse->packet[1],
     321             :                              psmouse->packet[2], psmouse->packet[3]);
     322           0 :                 return PSMOUSE_BAD_DATA;
     323             :         }
     324             : 
     325           0 :         priv->btn_left = pkt[0] & PS2_LEFT;
     326           0 :         priv->btn_right = pkt[0] & PS2_RIGHT;
     327             : 
     328           0 :         byd_report_input(psmouse);
     329             : 
     330             :         /* Reset time since last touch. */
     331           0 :         if (priv->touch) {
     332           0 :                 priv->last_touch_time = jiffies;
     333           0 :                 mod_timer(&priv->timer, jiffies + BYD_TOUCH_TIMEOUT);
     334             :         }
     335             : 
     336             :         return PSMOUSE_FULL_PACKET;
     337             : }
     338             : 
     339           0 : static int byd_reset_touchpad(struct psmouse *psmouse)
     340             : {
     341           0 :         struct ps2dev *ps2dev = &psmouse->ps2dev;
     342             :         u8 param[4];
     343             :         size_t i;
     344             : 
     345             :         static const struct {
     346             :                 u16 command;
     347             :                 u8 arg;
     348             :         } seq[] = {
     349             :                 /*
     350             :                  * Intellimouse initialization sequence, to get 4-byte instead
     351             :                  * of 3-byte packets.
     352             :                  */
     353             :                 { PSMOUSE_CMD_SETRATE, 0xC8 },
     354             :                 { PSMOUSE_CMD_SETRATE, 0x64 },
     355             :                 { PSMOUSE_CMD_SETRATE, 0x50 },
     356             :                 { PSMOUSE_CMD_GETID, 0 },
     357             :                 { PSMOUSE_CMD_ENABLE, 0 },
     358             :                 /*
     359             :                  * BYD-specific initialization, which enables absolute mode and
     360             :                  * (if desired), the touchpad's built-in gesture detection.
     361             :                  */
     362             :                 { 0x10E2, 0x00 },
     363             :                 { 0x10E0, 0x02 },
     364             :                 /* The touchpad should reply with 4 seemingly-random bytes */
     365             :                 { 0x14E0, 0x01 },
     366             :                 /* Pairs of parameters and values. */
     367             :                 { BYD_CMD_SET_HANDEDNESS, 0x01 },
     368             :                 { BYD_CMD_SET_PHYSICAL_BUTTONS, 0x04 },
     369             :                 { BYD_CMD_SET_TAP, 0x02 },
     370             :                 { BYD_CMD_SET_ONE_FINGER_SCROLL, 0x04 },
     371             :                 { BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC, 0x04 },
     372             :                 { BYD_CMD_SET_EDGE_MOTION, 0x01 },
     373             :                 { BYD_CMD_SET_PALM_CHECK, 0x00 },
     374             :                 { BYD_CMD_SET_MULTITOUCH, 0x02 },
     375             :                 { BYD_CMD_SET_TWO_FINGER_SCROLL, 0x04 },
     376             :                 { BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC, 0x04 },
     377             :                 { BYD_CMD_SET_LEFT_EDGE_REGION, 0x00 },
     378             :                 { BYD_CMD_SET_TOP_EDGE_REGION, 0x00 },
     379             :                 { BYD_CMD_SET_RIGHT_EDGE_REGION, 0x00 },
     380             :                 { BYD_CMD_SET_BOTTOM_EDGE_REGION, 0x00 },
     381             :                 { BYD_CMD_SET_ABSOLUTE_MODE, 0x02 },
     382             :                 /* Finalize initialization. */
     383             :                 { 0x10E0, 0x00 },
     384             :                 { 0x10E2, 0x01 },
     385             :         };
     386             : 
     387           0 :         for (i = 0; i < ARRAY_SIZE(seq); ++i) {
     388           0 :                 memset(param, 0, sizeof(param));
     389           0 :                 param[0] = seq[i].arg;
     390           0 :                 if (ps2_command(ps2dev, param, seq[i].command))
     391             :                         return -EIO;
     392             :         }
     393             : 
     394           0 :         psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
     395           0 :         return 0;
     396             : }
     397             : 
     398           0 : static int byd_reconnect(struct psmouse *psmouse)
     399             : {
     400           0 :         int retry = 0, error = 0;
     401             : 
     402             :         psmouse_dbg(psmouse, "Reconnect\n");
     403             :         do {
     404           0 :                 psmouse_reset(psmouse);
     405           0 :                 if (retry)
     406             :                         ssleep(1);
     407           0 :                 error = byd_detect(psmouse, 0);
     408           0 :         } while (error && ++retry < 3);
     409             : 
     410           0 :         if (error)
     411             :                 return error;
     412             : 
     413             :         psmouse_dbg(psmouse, "Reconnected after %d attempts\n", retry);
     414             : 
     415           0 :         error = byd_reset_touchpad(psmouse);
     416           0 :         if (error) {
     417           0 :                 psmouse_err(psmouse, "Unable to initialize device\n");
     418           0 :                 return error;
     419             :         }
     420             : 
     421             :         return 0;
     422             : }
     423             : 
     424           0 : static void byd_disconnect(struct psmouse *psmouse)
     425             : {
     426           0 :         struct byd_data *priv = psmouse->private;
     427             : 
     428           0 :         if (priv) {
     429           0 :                 del_timer(&priv->timer);
     430           0 :                 kfree(psmouse->private);
     431           0 :                 psmouse->private = NULL;
     432             :         }
     433           0 : }
     434             : 
     435           0 : int byd_detect(struct psmouse *psmouse, bool set_properties)
     436             : {
     437           0 :         struct ps2dev *ps2dev = &psmouse->ps2dev;
     438           0 :         u8 param[4] = {0x03, 0x00, 0x00, 0x00};
     439             : 
     440           0 :         if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
     441             :                 return -1;
     442           0 :         if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
     443             :                 return -1;
     444           0 :         if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
     445             :                 return -1;
     446           0 :         if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
     447             :                 return -1;
     448           0 :         if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
     449             :                 return -1;
     450             : 
     451           0 :         if (param[1] != 0x03 || param[2] != 0x64)
     452             :                 return -ENODEV;
     453             : 
     454             :         psmouse_dbg(psmouse, "BYD touchpad detected\n");
     455             : 
     456           0 :         if (set_properties) {
     457           0 :                 psmouse->vendor = "BYD";
     458           0 :                 psmouse->name = "TouchPad";
     459             :         }
     460             : 
     461             :         return 0;
     462             : }
     463             : 
     464           0 : int byd_init(struct psmouse *psmouse)
     465             : {
     466           0 :         struct input_dev *dev = psmouse->dev;
     467             :         struct byd_data *priv;
     468             : 
     469           0 :         if (psmouse_reset(psmouse))
     470             :                 return -EIO;
     471             : 
     472           0 :         if (byd_reset_touchpad(psmouse))
     473             :                 return -EIO;
     474             : 
     475           0 :         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
     476           0 :         if (!priv)
     477             :                 return -ENOMEM;
     478             : 
     479           0 :         priv->psmouse = psmouse;
     480           0 :         timer_setup(&priv->timer, byd_clear_touch, 0);
     481             : 
     482           0 :         psmouse->private = priv;
     483           0 :         psmouse->disconnect = byd_disconnect;
     484           0 :         psmouse->reconnect = byd_reconnect;
     485           0 :         psmouse->protocol_handler = byd_process_byte;
     486           0 :         psmouse->pktsize = 4;
     487           0 :         psmouse->resync_time = 0;
     488             : 
     489           0 :         __set_bit(INPUT_PROP_POINTER, dev->propbit);
     490             :         /* Touchpad */
     491           0 :         __set_bit(BTN_TOUCH, dev->keybit);
     492           0 :         __set_bit(BTN_TOOL_FINGER, dev->keybit);
     493             :         /* Buttons */
     494           0 :         __set_bit(BTN_LEFT, dev->keybit);
     495           0 :         __set_bit(BTN_RIGHT, dev->keybit);
     496           0 :         __clear_bit(BTN_MIDDLE, dev->keybit);
     497             : 
     498             :         /* Absolute position */
     499           0 :         __set_bit(EV_ABS, dev->evbit);
     500           0 :         input_set_abs_params(dev, ABS_X, 0, BYD_PAD_WIDTH, 0, 0);
     501           0 :         input_set_abs_params(dev, ABS_Y, 0, BYD_PAD_HEIGHT, 0, 0);
     502           0 :         input_abs_set_res(dev, ABS_X, BYD_PAD_RESOLUTION);
     503           0 :         input_abs_set_res(dev, ABS_Y, BYD_PAD_RESOLUTION);
     504             :         /* No relative support */
     505           0 :         __clear_bit(EV_REL, dev->evbit);
     506           0 :         __clear_bit(REL_X, dev->relbit);
     507           0 :         __clear_bit(REL_Y, dev->relbit);
     508             : 
     509             :         return 0;
     510             : }

Generated by: LCOV version 1.14