| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 1 | /* | 
|  | 2 | *	SEGA Dreamcast mouse driver | 
|  | 3 | *	Based on drivers/usb/usbmouse.c | 
|  | 4 | * | 
| Adrian McMenamin | 6b34808 | 2009-04-25 20:43:18 +0000 | [diff] [blame] | 5 | *	Copyright (c) Yaegashi Takeshi, 2001 | 
|  | 6 | *	Copyright (c) Adrian McMenamin, 2008 - 2009 | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 7 | */ | 
|  | 8 |  | 
|  | 9 | #include <linux/kernel.h> | 
|  | 10 | #include <linux/slab.h> | 
|  | 11 | #include <linux/input.h> | 
|  | 12 | #include <linux/module.h> | 
|  | 13 | #include <linux/init.h> | 
|  | 14 | #include <linux/timer.h> | 
|  | 15 | #include <linux/maple.h> | 
|  | 16 |  | 
|  | 17 | MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>"); | 
|  | 18 | MODULE_DESCRIPTION("SEGA Dreamcast mouse driver"); | 
|  | 19 | MODULE_LICENSE("GPL"); | 
|  | 20 |  | 
|  | 21 | struct dc_mouse { | 
|  | 22 | struct input_dev *dev; | 
|  | 23 | struct maple_device *mdev; | 
|  | 24 | }; | 
|  | 25 |  | 
|  | 26 | static void dc_mouse_callback(struct mapleq *mq) | 
|  | 27 | { | 
|  | 28 | int buttons, relx, rely, relz; | 
|  | 29 | struct maple_device *mapledev = mq->dev; | 
|  | 30 | struct dc_mouse *mse = maple_get_drvdata(mapledev); | 
|  | 31 | struct input_dev *dev = mse->dev; | 
| Adrian McMenamin | 6b34808 | 2009-04-25 20:43:18 +0000 | [diff] [blame] | 32 | unsigned char *res = mq->recvbuf->buf; | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 33 |  | 
|  | 34 | buttons = ~res[8]; | 
|  | 35 | relx = *(unsigned short *)(res + 12) - 512; | 
|  | 36 | rely = *(unsigned short *)(res + 14) - 512; | 
|  | 37 | relz = *(unsigned short *)(res + 16) - 512; | 
|  | 38 |  | 
|  | 39 | input_report_key(dev, BTN_LEFT,   buttons & 4); | 
|  | 40 | input_report_key(dev, BTN_MIDDLE, buttons & 9); | 
|  | 41 | input_report_key(dev, BTN_RIGHT,  buttons & 2); | 
|  | 42 | input_report_rel(dev, REL_X,      relx); | 
|  | 43 | input_report_rel(dev, REL_Y,      rely); | 
|  | 44 | input_report_rel(dev, REL_WHEEL,  relz); | 
|  | 45 | input_sync(dev); | 
|  | 46 | } | 
|  | 47 |  | 
|  | 48 | static int dc_mouse_open(struct input_dev *dev) | 
|  | 49 | { | 
| Adrian McMenamin | 6b34808 | 2009-04-25 20:43:18 +0000 | [diff] [blame] | 50 | struct dc_mouse *mse = maple_get_drvdata(to_maple_dev(&dev->dev)); | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 51 |  | 
|  | 52 | maple_getcond_callback(mse->mdev, dc_mouse_callback, HZ/50, | 
|  | 53 | MAPLE_FUNC_MOUSE); | 
|  | 54 |  | 
|  | 55 | return 0; | 
|  | 56 | } | 
|  | 57 |  | 
|  | 58 | static void dc_mouse_close(struct input_dev *dev) | 
|  | 59 | { | 
| Adrian McMenamin | 6b34808 | 2009-04-25 20:43:18 +0000 | [diff] [blame] | 60 | struct dc_mouse *mse = maple_get_drvdata(to_maple_dev(&dev->dev)); | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 61 |  | 
|  | 62 | maple_getcond_callback(mse->mdev, dc_mouse_callback, 0, | 
|  | 63 | MAPLE_FUNC_MOUSE); | 
|  | 64 | } | 
|  | 65 |  | 
| Adrian McMenamin | 6b34808 | 2009-04-25 20:43:18 +0000 | [diff] [blame] | 66 | /* allow the mouse to be used */ | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 67 | static int __devinit probe_maple_mouse(struct device *dev) | 
|  | 68 | { | 
|  | 69 | struct maple_device *mdev = to_maple_dev(dev); | 
|  | 70 | struct maple_driver *mdrv = to_maple_driver(dev->driver); | 
| Adrian McMenamin | 6b34808 | 2009-04-25 20:43:18 +0000 | [diff] [blame] | 71 | int error; | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 72 | struct input_dev *input_dev; | 
|  | 73 | struct dc_mouse *mse; | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 74 |  | 
|  | 75 | mse = kzalloc(sizeof(struct dc_mouse), GFP_KERNEL); | 
| Adrian McMenamin | 6b34808 | 2009-04-25 20:43:18 +0000 | [diff] [blame] | 76 | if (!mse) { | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 77 | error = -ENOMEM; | 
|  | 78 | goto fail; | 
|  | 79 | } | 
|  | 80 |  | 
| Adrian McMenamin | 6b34808 | 2009-04-25 20:43:18 +0000 | [diff] [blame] | 81 | input_dev = input_allocate_device(); | 
|  | 82 | if (!input_dev) { | 
|  | 83 | error = -ENOMEM; | 
|  | 84 | goto fail_nomem; | 
|  | 85 | } | 
|  | 86 |  | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 87 | mse->dev = input_dev; | 
|  | 88 | mse->mdev = mdev; | 
|  | 89 |  | 
|  | 90 | input_set_drvdata(input_dev, mse); | 
|  | 91 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); | 
|  | 92 | input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | | 
|  | 93 | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); | 
|  | 94 | input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) | | 
|  | 95 | BIT_MASK(REL_WHEEL); | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 96 | input_dev->open = dc_mouse_open; | 
|  | 97 | input_dev->close = dc_mouse_close; | 
| Adrian McMenamin | 6b34808 | 2009-04-25 20:43:18 +0000 | [diff] [blame] | 98 | input_dev->name = mdev->product_name; | 
|  | 99 | input_dev->id.bustype = BUS_HOST; | 
|  | 100 | error =	input_register_device(input_dev); | 
|  | 101 | if (error) | 
|  | 102 | goto fail_register; | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 103 |  | 
|  | 104 | mdev->driver = mdrv; | 
|  | 105 | maple_set_drvdata(mdev, mse); | 
|  | 106 |  | 
| Adrian McMenamin | 6b34808 | 2009-04-25 20:43:18 +0000 | [diff] [blame] | 107 | return error; | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 108 |  | 
| Adrian McMenamin | 6b34808 | 2009-04-25 20:43:18 +0000 | [diff] [blame] | 109 | fail_register: | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 110 | input_free_device(input_dev); | 
| Adrian McMenamin | 6b34808 | 2009-04-25 20:43:18 +0000 | [diff] [blame] | 111 | fail_nomem: | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 112 | kfree(mse); | 
| Adrian McMenamin | 6b34808 | 2009-04-25 20:43:18 +0000 | [diff] [blame] | 113 | fail: | 
| Adrian McMenamin | 03dd5e1 | 2009-01-29 22:56:08 -0800 | [diff] [blame] | 114 | return error; | 
|  | 115 | } | 
|  | 116 |  | 
|  | 117 | static int __devexit remove_maple_mouse(struct device *dev) | 
|  | 118 | { | 
|  | 119 | struct maple_device *mdev = to_maple_dev(dev); | 
|  | 120 | struct dc_mouse *mse = maple_get_drvdata(mdev); | 
|  | 121 |  | 
|  | 122 | mdev->callback = NULL; | 
|  | 123 | input_unregister_device(mse->dev); | 
|  | 124 | maple_set_drvdata(mdev, NULL); | 
|  | 125 | kfree(mse); | 
|  | 126 |  | 
|  | 127 | return 0; | 
|  | 128 | } | 
|  | 129 |  | 
|  | 130 | static struct maple_driver dc_mouse_driver = { | 
|  | 131 | .function =	MAPLE_FUNC_MOUSE, | 
|  | 132 | .drv = { | 
|  | 133 | .name = "Dreamcast_mouse", | 
|  | 134 | .probe = probe_maple_mouse, | 
|  | 135 | .remove = __devexit_p(remove_maple_mouse), | 
|  | 136 | }, | 
|  | 137 | }; | 
|  | 138 |  | 
|  | 139 | static int __init dc_mouse_init(void) | 
|  | 140 | { | 
|  | 141 | return maple_driver_register(&dc_mouse_driver); | 
|  | 142 | } | 
|  | 143 |  | 
|  | 144 | static void __exit dc_mouse_exit(void) | 
|  | 145 | { | 
|  | 146 | maple_driver_unregister(&dc_mouse_driver); | 
|  | 147 | } | 
|  | 148 |  | 
|  | 149 | module_init(dc_mouse_init); | 
|  | 150 | module_exit(dc_mouse_exit); |