109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
203dd5e1bSAdrian McMenamin /*
303dd5e1bSAdrian McMenamin * SEGA Dreamcast mouse driver
403dd5e1bSAdrian McMenamin * Based on drivers/usb/usbmouse.c
503dd5e1bSAdrian McMenamin *
66b348085SAdrian McMenamin * Copyright (c) Yaegashi Takeshi, 2001
76b348085SAdrian McMenamin * Copyright (c) Adrian McMenamin, 2008 - 2009
803dd5e1bSAdrian McMenamin */
903dd5e1bSAdrian McMenamin
1003dd5e1bSAdrian McMenamin #include <linux/kernel.h>
1103dd5e1bSAdrian McMenamin #include <linux/slab.h>
1203dd5e1bSAdrian McMenamin #include <linux/input.h>
1303dd5e1bSAdrian McMenamin #include <linux/module.h>
1403dd5e1bSAdrian McMenamin #include <linux/init.h>
1503dd5e1bSAdrian McMenamin #include <linux/timer.h>
1603dd5e1bSAdrian McMenamin #include <linux/maple.h>
1703dd5e1bSAdrian McMenamin
1803dd5e1bSAdrian McMenamin MODULE_AUTHOR("Adrian McMenamin <[email protected]>");
1903dd5e1bSAdrian McMenamin MODULE_DESCRIPTION("SEGA Dreamcast mouse driver");
2003dd5e1bSAdrian McMenamin MODULE_LICENSE("GPL");
2103dd5e1bSAdrian McMenamin
2203dd5e1bSAdrian McMenamin struct dc_mouse {
2303dd5e1bSAdrian McMenamin struct input_dev *dev;
2403dd5e1bSAdrian McMenamin struct maple_device *mdev;
2503dd5e1bSAdrian McMenamin };
2603dd5e1bSAdrian McMenamin
dc_mouse_callback(struct mapleq * mq)2703dd5e1bSAdrian McMenamin static void dc_mouse_callback(struct mapleq *mq)
2803dd5e1bSAdrian McMenamin {
2903dd5e1bSAdrian McMenamin int buttons, relx, rely, relz;
3003dd5e1bSAdrian McMenamin struct maple_device *mapledev = mq->dev;
3103dd5e1bSAdrian McMenamin struct dc_mouse *mse = maple_get_drvdata(mapledev);
3203dd5e1bSAdrian McMenamin struct input_dev *dev = mse->dev;
336b348085SAdrian McMenamin unsigned char *res = mq->recvbuf->buf;
3403dd5e1bSAdrian McMenamin
3503dd5e1bSAdrian McMenamin buttons = ~res[8];
3603dd5e1bSAdrian McMenamin relx = *(unsigned short *)(res + 12) - 512;
3703dd5e1bSAdrian McMenamin rely = *(unsigned short *)(res + 14) - 512;
3803dd5e1bSAdrian McMenamin relz = *(unsigned short *)(res + 16) - 512;
3903dd5e1bSAdrian McMenamin
4003dd5e1bSAdrian McMenamin input_report_key(dev, BTN_LEFT, buttons & 4);
4103dd5e1bSAdrian McMenamin input_report_key(dev, BTN_MIDDLE, buttons & 9);
4203dd5e1bSAdrian McMenamin input_report_key(dev, BTN_RIGHT, buttons & 2);
4303dd5e1bSAdrian McMenamin input_report_rel(dev, REL_X, relx);
4403dd5e1bSAdrian McMenamin input_report_rel(dev, REL_Y, rely);
4503dd5e1bSAdrian McMenamin input_report_rel(dev, REL_WHEEL, relz);
4603dd5e1bSAdrian McMenamin input_sync(dev);
4703dd5e1bSAdrian McMenamin }
4803dd5e1bSAdrian McMenamin
dc_mouse_open(struct input_dev * dev)4903dd5e1bSAdrian McMenamin static int dc_mouse_open(struct input_dev *dev)
5003dd5e1bSAdrian McMenamin {
516b348085SAdrian McMenamin struct dc_mouse *mse = maple_get_drvdata(to_maple_dev(&dev->dev));
5203dd5e1bSAdrian McMenamin
5303dd5e1bSAdrian McMenamin maple_getcond_callback(mse->mdev, dc_mouse_callback, HZ/50,
5403dd5e1bSAdrian McMenamin MAPLE_FUNC_MOUSE);
5503dd5e1bSAdrian McMenamin
5603dd5e1bSAdrian McMenamin return 0;
5703dd5e1bSAdrian McMenamin }
5803dd5e1bSAdrian McMenamin
dc_mouse_close(struct input_dev * dev)5903dd5e1bSAdrian McMenamin static void dc_mouse_close(struct input_dev *dev)
6003dd5e1bSAdrian McMenamin {
616b348085SAdrian McMenamin struct dc_mouse *mse = maple_get_drvdata(to_maple_dev(&dev->dev));
6203dd5e1bSAdrian McMenamin
6303dd5e1bSAdrian McMenamin maple_getcond_callback(mse->mdev, dc_mouse_callback, 0,
6403dd5e1bSAdrian McMenamin MAPLE_FUNC_MOUSE);
6503dd5e1bSAdrian McMenamin }
6603dd5e1bSAdrian McMenamin
676b348085SAdrian McMenamin /* allow the mouse to be used */
probe_maple_mouse(struct device * dev)685298cc4cSBill Pemberton static int probe_maple_mouse(struct device *dev)
6903dd5e1bSAdrian McMenamin {
7003dd5e1bSAdrian McMenamin struct maple_device *mdev = to_maple_dev(dev);
7103dd5e1bSAdrian McMenamin struct maple_driver *mdrv = to_maple_driver(dev->driver);
726b348085SAdrian McMenamin int error;
7303dd5e1bSAdrian McMenamin struct input_dev *input_dev;
7403dd5e1bSAdrian McMenamin struct dc_mouse *mse;
7503dd5e1bSAdrian McMenamin
76*dc2f1423SErick Archer mse = kzalloc(sizeof(*mse), GFP_KERNEL);
776b348085SAdrian McMenamin if (!mse) {
7803dd5e1bSAdrian McMenamin error = -ENOMEM;
7903dd5e1bSAdrian McMenamin goto fail;
8003dd5e1bSAdrian McMenamin }
8103dd5e1bSAdrian McMenamin
826b348085SAdrian McMenamin input_dev = input_allocate_device();
836b348085SAdrian McMenamin if (!input_dev) {
846b348085SAdrian McMenamin error = -ENOMEM;
856b348085SAdrian McMenamin goto fail_nomem;
866b348085SAdrian McMenamin }
876b348085SAdrian McMenamin
8803dd5e1bSAdrian McMenamin mse->dev = input_dev;
8903dd5e1bSAdrian McMenamin mse->mdev = mdev;
9003dd5e1bSAdrian McMenamin
9103dd5e1bSAdrian McMenamin input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
9203dd5e1bSAdrian McMenamin input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
9303dd5e1bSAdrian McMenamin BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
9403dd5e1bSAdrian McMenamin input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) |
9503dd5e1bSAdrian McMenamin BIT_MASK(REL_WHEEL);
9603dd5e1bSAdrian McMenamin input_dev->open = dc_mouse_open;
9703dd5e1bSAdrian McMenamin input_dev->close = dc_mouse_close;
986b348085SAdrian McMenamin input_dev->name = mdev->product_name;
996b348085SAdrian McMenamin input_dev->id.bustype = BUS_HOST;
1006b348085SAdrian McMenamin error = input_register_device(input_dev);
1016b348085SAdrian McMenamin if (error)
1026b348085SAdrian McMenamin goto fail_register;
10303dd5e1bSAdrian McMenamin
10403dd5e1bSAdrian McMenamin mdev->driver = mdrv;
10503dd5e1bSAdrian McMenamin maple_set_drvdata(mdev, mse);
10603dd5e1bSAdrian McMenamin
1076b348085SAdrian McMenamin return error;
10803dd5e1bSAdrian McMenamin
1096b348085SAdrian McMenamin fail_register:
11003dd5e1bSAdrian McMenamin input_free_device(input_dev);
1116b348085SAdrian McMenamin fail_nomem:
11203dd5e1bSAdrian McMenamin kfree(mse);
1136b348085SAdrian McMenamin fail:
11403dd5e1bSAdrian McMenamin return error;
11503dd5e1bSAdrian McMenamin }
11603dd5e1bSAdrian McMenamin
remove_maple_mouse(struct device * dev)117e2619cf7SBill Pemberton static int remove_maple_mouse(struct device *dev)
11803dd5e1bSAdrian McMenamin {
11903dd5e1bSAdrian McMenamin struct maple_device *mdev = to_maple_dev(dev);
12003dd5e1bSAdrian McMenamin struct dc_mouse *mse = maple_get_drvdata(mdev);
12103dd5e1bSAdrian McMenamin
12203dd5e1bSAdrian McMenamin mdev->callback = NULL;
12303dd5e1bSAdrian McMenamin input_unregister_device(mse->dev);
12403dd5e1bSAdrian McMenamin maple_set_drvdata(mdev, NULL);
12503dd5e1bSAdrian McMenamin kfree(mse);
12603dd5e1bSAdrian McMenamin
12703dd5e1bSAdrian McMenamin return 0;
12803dd5e1bSAdrian McMenamin }
12903dd5e1bSAdrian McMenamin
13003dd5e1bSAdrian McMenamin static struct maple_driver dc_mouse_driver = {
13103dd5e1bSAdrian McMenamin .function = MAPLE_FUNC_MOUSE,
13203dd5e1bSAdrian McMenamin .drv = {
13303dd5e1bSAdrian McMenamin .name = "Dreamcast_mouse",
13403dd5e1bSAdrian McMenamin .probe = probe_maple_mouse,
1351cb0aa88SBill Pemberton .remove = remove_maple_mouse,
13603dd5e1bSAdrian McMenamin },
13703dd5e1bSAdrian McMenamin };
13803dd5e1bSAdrian McMenamin
dc_mouse_init(void)13903dd5e1bSAdrian McMenamin static int __init dc_mouse_init(void)
14003dd5e1bSAdrian McMenamin {
14103dd5e1bSAdrian McMenamin return maple_driver_register(&dc_mouse_driver);
14203dd5e1bSAdrian McMenamin }
14303dd5e1bSAdrian McMenamin
dc_mouse_exit(void)14403dd5e1bSAdrian McMenamin static void __exit dc_mouse_exit(void)
14503dd5e1bSAdrian McMenamin {
14603dd5e1bSAdrian McMenamin maple_driver_unregister(&dc_mouse_driver);
14703dd5e1bSAdrian McMenamin }
14803dd5e1bSAdrian McMenamin
14903dd5e1bSAdrian McMenamin module_init(dc_mouse_init);
15003dd5e1bSAdrian McMenamin module_exit(dc_mouse_exit);
151