11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz> 3598972d4fb39c8a0826b396e45dc2a8c1dbe4f11Johann Deneux * Copyright (c) 2001, 2007 Johann Deneux <johann.deneux@gmail.com> 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USB/RS232 I-Force joysticks and wheels. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Should you need to contact me, the author, you can do so either by 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "iforce.h" 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid iforce_serial_xmit(struct iforce *iforce) 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char cs; 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags); 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&iforce->xmit_lock, flags); 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsagain: 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (iforce->xmit.head == iforce->xmit.tail) { 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&iforce->xmit_lock, flags); 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs = 0x2b; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_write(iforce->serio, 0x2b); 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs ^= iforce->xmit.buf[iforce->xmit.tail]; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds XMIT_INC(iforce->xmit.tail, 1); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) { 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cs ^= iforce->xmit.buf[iforce->xmit.tail]; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds XMIT_INC(iforce->xmit.tail, 1); 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_write(iforce->serio, cs); 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto again; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&iforce->xmit_lock, flags); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void iforce_serio_write_wakeup(struct serio *serio) 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iforce *iforce = serio_get_drvdata(serio); 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce_serial_xmit(iforce); 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t iforce_serio_irq(struct serio *serio, 827d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells unsigned char data, unsigned int flags) 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iforce *iforce = serio_get_drvdata(serio); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!iforce->pkt) { 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data == 0x2b) 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce->pkt = 1; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!iforce->id) { 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data > 3 && data != 0xff) 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce->pkt = 0; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce->id = data; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!iforce->len) { 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data > IFORCE_MAX_LENGTH) { 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce->pkt = 0; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce->id = 0; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce->len = data; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (iforce->idx < iforce->len) { 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce->csum += iforce->data[iforce->idx++] = data; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (iforce->idx == iforce->len) { 1167d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce->pkt = 0; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce->id = 0; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce->len = 0; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce->idx = 0; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce->csum = 0; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iforce *iforce; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13217dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov iforce = kzalloc(sizeof(struct iforce), GFP_KERNEL); 13317dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov if (!iforce) 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce->bus = IFORCE_232; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iforce->serio = serio; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_set_drvdata(serio, iforce); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = serio_open(serio, drv); 142127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov if (err) 143127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov goto fail1; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14517dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov err = iforce_init_device(iforce); 146127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov if (err) 147127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov goto fail2; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 150127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov 151127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov fail2: serio_close(serio); 152127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov fail1: serio_set_drvdata(serio, NULL); 153127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov kfree(iforce); 154127278ce2254c61f1346500374d61e33f74a8729Dmitry Torokhov return err; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void iforce_serio_disconnect(struct serio *serio) 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iforce *iforce = serio_get_drvdata(serio); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16117dd3f0f7aa729a042af5d3318ff9b3e7781b45bDmitry Torokhov input_unregister_device(iforce->dev); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_close(serio); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_set_drvdata(serio, NULL); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(iforce); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct serio_device_id iforce_serio_ids[] = { 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .type = SERIO_RS232, 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .proto = SERIO_IFORCE, 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id = SERIO_ANY, 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .extra = SERIO_ANY, 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0 } 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(serio, iforce_serio_ids); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct serio_driver iforce_serio_drv = { 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver = { 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "iforce", 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .description = "RS232 I-Force joysticks and wheels driver", 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = iforce_serio_ids, 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_wakeup = iforce_serio_write_wakeup, 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .interrupt = iforce_serio_irq, 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .connect = iforce_serio_connect, 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = iforce_serio_disconnect, 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 190