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 /* 10 */ 11 12 #include "iforce.h" 13 14 void iforce_serial_xmit(struct iforce *iforce) 15 { 16 unsigned char cs; 17 int i; 18 unsigned long flags; 19 20 if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { 21 set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags); 22 return; 23 } 24 25 spin_lock_irqsave(&iforce->xmit_lock, flags); 26 27 again: 28 if (iforce->xmit.head == iforce->xmit.tail) { 29 clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); 30 spin_unlock_irqrestore(&iforce->xmit_lock, flags); 31 return; 32 } 33 34 cs = 0x2b; 35 36 serio_write(iforce->serio, 0x2b); 37 38 serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); 39 cs ^= iforce->xmit.buf[iforce->xmit.tail]; 40 XMIT_INC(iforce->xmit.tail, 1); 41 42 for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) { 43 serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); 44 cs ^= iforce->xmit.buf[iforce->xmit.tail]; 45 XMIT_INC(iforce->xmit.tail, 1); 46 } 47 48 serio_write(iforce->serio, cs); 49 50 if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) 51 goto again; 52 53 clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); 54 55 spin_unlock_irqrestore(&iforce->xmit_lock, flags); 56 } 57 58 static void iforce_serio_write_wakeup(struct serio *serio) 59 { 60 struct iforce *iforce = serio_get_drvdata(serio); 61 62 iforce_serial_xmit(iforce); 63 } 64 65 static irqreturn_t iforce_serio_irq(struct serio *serio, 66 unsigned char data, unsigned int flags) 67 { 68 struct iforce *iforce = serio_get_drvdata(serio); 69 70 if (!iforce->pkt) { 71 if (data == 0x2b) 72 iforce->pkt = 1; 73 goto out; 74 } 75 76 if (!iforce->id) { 77 if (data > 3 && data != 0xff) 78 iforce->pkt = 0; 79 else 80 iforce->id = data; 81 goto out; 82 } 83 84 if (!iforce->len) { 85 if (data > IFORCE_MAX_LENGTH) { 86 iforce->pkt = 0; 87 iforce->id = 0; 88 } else { 89 iforce->len = data; 90 } 91 goto out; 92 } 93 94 if (iforce->idx < iforce->len) { 95 iforce->csum += iforce->data[iforce->idx++] = data; 96 goto out; 97 } 98 99 if (iforce->idx == iforce->len) { 100 iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); 101 iforce->pkt = 0; 102 iforce->id = 0; 103 iforce->len = 0; 104 iforce->idx = 0; 105 iforce->csum = 0; 106 } 107 out: 108 return IRQ_HANDLED; 109 } 110 111 static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) 112 { 113 struct iforce *iforce; 114 int err; 115 116 iforce = kzalloc(sizeof(struct iforce), GFP_KERNEL); 117 if (!iforce) 118 return -ENOMEM; 119 120 iforce->bus = IFORCE_232; 121 iforce->serio = serio; 122 123 serio_set_drvdata(serio, iforce); 124 125 err = serio_open(serio, drv); 126 if (err) 127 goto fail1; 128 129 err = iforce_init_device(iforce); 130 if (err) 131 goto fail2; 132 133 return 0; 134 135 fail2: serio_close(serio); 136 fail1: serio_set_drvdata(serio, NULL); 137 kfree(iforce); 138 return err; 139 } 140 141 static void iforce_serio_disconnect(struct serio *serio) 142 { 143 struct iforce *iforce = serio_get_drvdata(serio); 144 145 input_unregister_device(iforce->dev); 146 serio_close(serio); 147 serio_set_drvdata(serio, NULL); 148 kfree(iforce); 149 } 150 151 static const struct serio_device_id iforce_serio_ids[] = { 152 { 153 .type = SERIO_RS232, 154 .proto = SERIO_IFORCE, 155 .id = SERIO_ANY, 156 .extra = SERIO_ANY, 157 }, 158 { 0 } 159 }; 160 161 MODULE_DEVICE_TABLE(serio, iforce_serio_ids); 162 163 struct serio_driver iforce_serio_drv = { 164 .driver = { 165 .name = "iforce", 166 }, 167 .description = "RS232 I-Force joysticks and wheels driver", 168 .id_table = iforce_serio_ids, 169 .write_wakeup = iforce_serio_write_wakeup, 170 .interrupt = iforce_serio_irq, 171 .connect = iforce_serio_connect, 172 .disconnect = iforce_serio_disconnect, 173 }; 174