linux/drivers/input/joystick/iforce/iforce-serio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
   4 *  Copyright (c) 2001, 2007 Johann Deneux <johann.deneux@gmail.com>
   5 *
   6 *  USB/RS232 I-Force joysticks and wheels.
   7 */
   8
   9#include <linux/serio.h>
  10#include "iforce.h"
  11
  12struct iforce_serio {
  13        struct iforce iforce;
  14
  15        struct serio *serio;
  16        int idx, pkt, len, id;
  17        u8 csum;
  18        u8 expect_packet;
  19        u8 cmd_response[IFORCE_MAX_LENGTH];
  20        u8 cmd_response_len;
  21        u8 data_in[IFORCE_MAX_LENGTH];
  22};
  23
  24static void iforce_serio_xmit(struct iforce *iforce)
  25{
  26        struct iforce_serio *iforce_serio = container_of(iforce,
  27                                                         struct iforce_serio,
  28                                                         iforce);
  29        unsigned char cs;
  30        int i;
  31        unsigned long flags;
  32
  33        if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
  34                set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags);
  35                return;
  36        }
  37
  38        spin_lock_irqsave(&iforce->xmit_lock, flags);
  39
  40again:
  41        if (iforce->xmit.head == iforce->xmit.tail) {
  42                clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
  43                spin_unlock_irqrestore(&iforce->xmit_lock, flags);
  44                return;
  45        }
  46
  47        cs = 0x2b;
  48
  49        serio_write(iforce_serio->serio, 0x2b);
  50
  51        serio_write(iforce_serio->serio, iforce->xmit.buf[iforce->xmit.tail]);
  52        cs ^= iforce->xmit.buf[iforce->xmit.tail];
  53        XMIT_INC(iforce->xmit.tail, 1);
  54
  55        for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) {
  56                serio_write(iforce_serio->serio,
  57                            iforce->xmit.buf[iforce->xmit.tail]);
  58                cs ^= iforce->xmit.buf[iforce->xmit.tail];
  59                XMIT_INC(iforce->xmit.tail, 1);
  60        }
  61
  62        serio_write(iforce_serio->serio, cs);
  63
  64        if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
  65                goto again;
  66
  67        clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
  68
  69        spin_unlock_irqrestore(&iforce->xmit_lock, flags);
  70}
  71
  72static int iforce_serio_get_id(struct iforce *iforce, u8 id,
  73                               u8 *response_data, size_t *response_len)
  74{
  75        struct iforce_serio *iforce_serio = container_of(iforce,
  76                                                         struct iforce_serio,
  77                                                         iforce);
  78
  79        iforce_serio->expect_packet = HI(FF_CMD_QUERY);
  80        iforce_serio->cmd_response_len = 0;
  81
  82        iforce_send_packet(iforce, FF_CMD_QUERY, &id);
  83
  84        wait_event_interruptible_timeout(iforce->wait,
  85                                         !iforce_serio->expect_packet, HZ);
  86
  87        if (iforce_serio->expect_packet) {
  88                iforce_serio->expect_packet = 0;
  89                return -ETIMEDOUT;
  90        }
  91
  92        if (iforce_serio->cmd_response[0] != id)
  93                return -EIO;
  94
  95        memcpy(response_data, iforce_serio->cmd_response,
  96               iforce_serio->cmd_response_len);
  97        *response_len = iforce_serio->cmd_response_len;
  98
  99        return 0;
 100}
 101
 102static int iforce_serio_start_io(struct iforce *iforce)
 103{
 104        /* No special handling required */
 105        return 0;
 106}
 107
 108static void iforce_serio_stop_io(struct iforce *iforce)
 109{
 110        //TODO: Wait for the last packets to be sent
 111}
 112
 113static const struct iforce_xport_ops iforce_serio_xport_ops = {
 114        .xmit           = iforce_serio_xmit,
 115        .get_id         = iforce_serio_get_id,
 116        .start_io       = iforce_serio_start_io,
 117        .stop_io        = iforce_serio_stop_io,
 118};
 119
 120static void iforce_serio_write_wakeup(struct serio *serio)
 121{
 122        struct iforce *iforce = serio_get_drvdata(serio);
 123
 124        iforce_serio_xmit(iforce);
 125}
 126
 127static irqreturn_t iforce_serio_irq(struct serio *serio,
 128                                    unsigned char data, unsigned int flags)
 129{
 130        struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
 131        struct iforce *iforce = &iforce_serio->iforce;
 132
 133        if (!iforce_serio->pkt) {
 134                if (data == 0x2b)
 135                        iforce_serio->pkt = 1;
 136                goto out;
 137        }
 138
 139        if (!iforce_serio->id) {
 140                if (data > 3 && data != 0xff)
 141                        iforce_serio->pkt = 0;
 142                else
 143                        iforce_serio->id = data;
 144                goto out;
 145        }
 146
 147        if (!iforce_serio->len) {
 148                if (data > IFORCE_MAX_LENGTH) {
 149                        iforce_serio->pkt = 0;
 150                        iforce_serio->id = 0;
 151                } else {
 152                        iforce_serio->len = data;
 153                }
 154                goto out;
 155        }
 156
 157        if (iforce_serio->idx < iforce_serio->len) {
 158                iforce_serio->data_in[iforce_serio->idx++] = data;
 159                iforce_serio->csum += data;
 160                goto out;
 161        }
 162
 163        if (iforce_serio->idx == iforce_serio->len) {
 164                /* Handle command completion */
 165                if (iforce_serio->expect_packet == iforce_serio->id) {
 166                        iforce_serio->expect_packet = 0;
 167                        memcpy(iforce_serio->cmd_response,
 168                               iforce_serio->data_in, IFORCE_MAX_LENGTH);
 169                        iforce_serio->cmd_response_len = iforce_serio->len;
 170
 171                        /* Signal that command is done */
 172                        wake_up(&iforce->wait);
 173                } else if (likely(iforce->type)) {
 174                        iforce_process_packet(iforce, iforce_serio->id,
 175                                              iforce_serio->data_in,
 176                                              iforce_serio->len);
 177                }
 178
 179                iforce_serio->pkt = 0;
 180                iforce_serio->id  = 0;
 181                iforce_serio->len = 0;
 182                iforce_serio->idx = 0;
 183                iforce_serio->csum = 0;
 184        }
 185out:
 186        return IRQ_HANDLED;
 187}
 188
 189static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
 190{
 191        struct iforce_serio *iforce_serio;
 192        int err;
 193
 194        iforce_serio = kzalloc(sizeof(*iforce_serio), GFP_KERNEL);
 195        if (!iforce_serio)
 196                return -ENOMEM;
 197
 198        iforce_serio->iforce.xport_ops = &iforce_serio_xport_ops;
 199
 200        iforce_serio->serio = serio;
 201        serio_set_drvdata(serio, iforce_serio);
 202
 203        err = serio_open(serio, drv);
 204        if (err)
 205                goto fail1;
 206
 207        err = iforce_init_device(&serio->dev, BUS_RS232, &iforce_serio->iforce);
 208        if (err)
 209                goto fail2;
 210
 211        return 0;
 212
 213 fail2: serio_close(serio);
 214 fail1: serio_set_drvdata(serio, NULL);
 215        kfree(iforce_serio);
 216        return err;
 217}
 218
 219static void iforce_serio_disconnect(struct serio *serio)
 220{
 221        struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
 222
 223        input_unregister_device(iforce_serio->iforce.dev);
 224        serio_close(serio);
 225        serio_set_drvdata(serio, NULL);
 226        kfree(iforce_serio);
 227}
 228
 229static const struct serio_device_id iforce_serio_ids[] = {
 230        {
 231                .type   = SERIO_RS232,
 232                .proto  = SERIO_IFORCE,
 233                .id     = SERIO_ANY,
 234                .extra  = SERIO_ANY,
 235        },
 236        { 0 }
 237};
 238
 239MODULE_DEVICE_TABLE(serio, iforce_serio_ids);
 240
 241struct serio_driver iforce_serio_drv = {
 242        .driver         = {
 243                .name   = "iforce",
 244        },
 245        .description    = "RS232 I-Force joysticks and wheels driver",
 246        .id_table       = iforce_serio_ids,
 247        .write_wakeup   = iforce_serio_write_wakeup,
 248        .interrupt      = iforce_serio_irq,
 249        .connect        = iforce_serio_connect,
 250        .disconnect     = iforce_serio_disconnect,
 251};
 252
 253module_serio_driver(iforce_serio_drv);
 254
 255MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
 256MODULE_DESCRIPTION("RS232 I-Force joysticks and wheels driver");
 257MODULE_LICENSE("GPL");
 258