162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * SEGA Dreamcast controller driver 462306a36Sopenharmony_ci * Based on drivers/usb/iforce.c 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright Yaegashi Takeshi, 2001 762306a36Sopenharmony_ci * Adrian McMenamin, 2008 - 2009 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/input.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/timer.h> 1662306a36Sopenharmony_ci#include <linux/maple.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciMODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>"); 1962306a36Sopenharmony_ciMODULE_DESCRIPTION("SEGA Dreamcast controller driver"); 2062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct dc_pad { 2362306a36Sopenharmony_ci struct input_dev *dev; 2462306a36Sopenharmony_ci struct maple_device *mdev; 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic void dc_pad_callback(struct mapleq *mq) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci unsigned short buttons; 3062306a36Sopenharmony_ci struct maple_device *mapledev = mq->dev; 3162306a36Sopenharmony_ci struct dc_pad *pad = maple_get_drvdata(mapledev); 3262306a36Sopenharmony_ci struct input_dev *dev = pad->dev; 3362306a36Sopenharmony_ci unsigned char *res = mq->recvbuf->buf; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci buttons = ~le16_to_cpup((__le16 *)(res + 8)); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci input_report_abs(dev, ABS_HAT0Y, 3862306a36Sopenharmony_ci (buttons & 0x0010 ? -1 : 0) + (buttons & 0x0020 ? 1 : 0)); 3962306a36Sopenharmony_ci input_report_abs(dev, ABS_HAT0X, 4062306a36Sopenharmony_ci (buttons & 0x0040 ? -1 : 0) + (buttons & 0x0080 ? 1 : 0)); 4162306a36Sopenharmony_ci input_report_abs(dev, ABS_HAT1Y, 4262306a36Sopenharmony_ci (buttons & 0x1000 ? -1 : 0) + (buttons & 0x2000 ? 1 : 0)); 4362306a36Sopenharmony_ci input_report_abs(dev, ABS_HAT1X, 4462306a36Sopenharmony_ci (buttons & 0x4000 ? -1 : 0) + (buttons & 0x8000 ? 1 : 0)); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci input_report_key(dev, BTN_C, buttons & 0x0001); 4762306a36Sopenharmony_ci input_report_key(dev, BTN_B, buttons & 0x0002); 4862306a36Sopenharmony_ci input_report_key(dev, BTN_A, buttons & 0x0004); 4962306a36Sopenharmony_ci input_report_key(dev, BTN_START, buttons & 0x0008); 5062306a36Sopenharmony_ci input_report_key(dev, BTN_Z, buttons & 0x0100); 5162306a36Sopenharmony_ci input_report_key(dev, BTN_Y, buttons & 0x0200); 5262306a36Sopenharmony_ci input_report_key(dev, BTN_X, buttons & 0x0400); 5362306a36Sopenharmony_ci input_report_key(dev, BTN_SELECT, buttons & 0x0800); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci input_report_abs(dev, ABS_GAS, res[10]); 5662306a36Sopenharmony_ci input_report_abs(dev, ABS_BRAKE, res[11]); 5762306a36Sopenharmony_ci input_report_abs(dev, ABS_X, res[12]); 5862306a36Sopenharmony_ci input_report_abs(dev, ABS_Y, res[13]); 5962306a36Sopenharmony_ci input_report_abs(dev, ABS_RX, res[14]); 6062306a36Sopenharmony_ci input_report_abs(dev, ABS_RY, res[15]); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic int dc_pad_open(struct input_dev *dev) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct dc_pad *pad = dev_get_platdata(&dev->dev); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci maple_getcond_callback(pad->mdev, dc_pad_callback, HZ/20, 6862306a36Sopenharmony_ci MAPLE_FUNC_CONTROLLER); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return 0; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic void dc_pad_close(struct input_dev *dev) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct dc_pad *pad = dev_get_platdata(&dev->dev); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci maple_getcond_callback(pad->mdev, dc_pad_callback, 0, 7862306a36Sopenharmony_ci MAPLE_FUNC_CONTROLLER); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* allow the controller to be used */ 8262306a36Sopenharmony_cistatic int probe_maple_controller(struct device *dev) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci static const short btn_bit[32] = { 8562306a36Sopenharmony_ci BTN_C, BTN_B, BTN_A, BTN_START, -1, -1, -1, -1, 8662306a36Sopenharmony_ci BTN_Z, BTN_Y, BTN_X, BTN_SELECT, -1, -1, -1, -1, 8762306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8862306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 8962306a36Sopenharmony_ci }; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci static const short abs_bit[32] = { 9262306a36Sopenharmony_ci -1, -1, -1, -1, ABS_HAT0Y, ABS_HAT0Y, ABS_HAT0X, ABS_HAT0X, 9362306a36Sopenharmony_ci -1, -1, -1, -1, ABS_HAT1Y, ABS_HAT1Y, ABS_HAT1X, ABS_HAT1X, 9462306a36Sopenharmony_ci ABS_GAS, ABS_BRAKE, ABS_X, ABS_Y, ABS_RX, ABS_RY, -1, -1, 9562306a36Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, 9662306a36Sopenharmony_ci }; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci struct maple_device *mdev = to_maple_dev(dev); 9962306a36Sopenharmony_ci struct maple_driver *mdrv = to_maple_driver(dev->driver); 10062306a36Sopenharmony_ci int i, error; 10162306a36Sopenharmony_ci struct dc_pad *pad; 10262306a36Sopenharmony_ci struct input_dev *idev; 10362306a36Sopenharmony_ci unsigned long data = be32_to_cpu(mdev->devinfo.function_data[0]); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci pad = kzalloc(sizeof(struct dc_pad), GFP_KERNEL); 10662306a36Sopenharmony_ci idev = input_allocate_device(); 10762306a36Sopenharmony_ci if (!pad || !idev) { 10862306a36Sopenharmony_ci error = -ENOMEM; 10962306a36Sopenharmony_ci goto fail; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci pad->dev = idev; 11362306a36Sopenharmony_ci pad->mdev = mdev; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci idev->open = dc_pad_open; 11662306a36Sopenharmony_ci idev->close = dc_pad_close; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 11962306a36Sopenharmony_ci if (data & (1 << i)) { 12062306a36Sopenharmony_ci if (btn_bit[i] >= 0) 12162306a36Sopenharmony_ci __set_bit(btn_bit[i], idev->keybit); 12262306a36Sopenharmony_ci else if (abs_bit[i] >= 0) 12362306a36Sopenharmony_ci __set_bit(abs_bit[i], idev->absbit); 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (idev->keybit[BIT_WORD(BTN_JOYSTICK)]) 12862306a36Sopenharmony_ci idev->evbit[0] |= BIT_MASK(EV_KEY); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (idev->absbit[0]) 13162306a36Sopenharmony_ci idev->evbit[0] |= BIT_MASK(EV_ABS); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci for (i = ABS_X; i <= ABS_BRAKE; i++) 13462306a36Sopenharmony_ci input_set_abs_params(idev, i, 0, 255, 0, 0); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci for (i = ABS_HAT0X; i <= ABS_HAT3Y; i++) 13762306a36Sopenharmony_ci input_set_abs_params(idev, i, 1, -1, 0, 0); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci idev->dev.platform_data = pad; 14062306a36Sopenharmony_ci idev->dev.parent = &mdev->dev; 14162306a36Sopenharmony_ci idev->name = mdev->product_name; 14262306a36Sopenharmony_ci idev->id.bustype = BUS_HOST; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci error = input_register_device(idev); 14562306a36Sopenharmony_ci if (error) 14662306a36Sopenharmony_ci goto fail; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci mdev->driver = mdrv; 14962306a36Sopenharmony_ci maple_set_drvdata(mdev, pad); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cifail: 15462306a36Sopenharmony_ci input_free_device(idev); 15562306a36Sopenharmony_ci kfree(pad); 15662306a36Sopenharmony_ci maple_set_drvdata(mdev, NULL); 15762306a36Sopenharmony_ci return error; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic int remove_maple_controller(struct device *dev) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct maple_device *mdev = to_maple_dev(dev); 16362306a36Sopenharmony_ci struct dc_pad *pad = maple_get_drvdata(mdev); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci mdev->callback = NULL; 16662306a36Sopenharmony_ci input_unregister_device(pad->dev); 16762306a36Sopenharmony_ci maple_set_drvdata(mdev, NULL); 16862306a36Sopenharmony_ci kfree(pad); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return 0; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic struct maple_driver dc_pad_driver = { 17462306a36Sopenharmony_ci .function = MAPLE_FUNC_CONTROLLER, 17562306a36Sopenharmony_ci .drv = { 17662306a36Sopenharmony_ci .name = "Dreamcast_controller", 17762306a36Sopenharmony_ci .probe = probe_maple_controller, 17862306a36Sopenharmony_ci .remove = remove_maple_controller, 17962306a36Sopenharmony_ci }, 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic int __init dc_pad_init(void) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci return maple_driver_register(&dc_pad_driver); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic void __exit dc_pad_exit(void) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci maple_driver_unregister(&dc_pad_driver); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cimodule_init(dc_pad_init); 19362306a36Sopenharmony_cimodule_exit(dc_pad_exit); 194