-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 126863 b: refs/heads/master c: 01461d7 h: refs/heads/master i: 126861: f3166ee 126859: 541bd47 126855: efe8f9f 126847: 50bdedb v: v3
- Loading branch information
Adrian McMenamin
authored and
Dmitry Torokhov
committed
Dec 30, 2008
1 parent
d4ba35d
commit 79bdbd9
Showing
4 changed files
with
207 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: 2a3ec3265741c3b2a7ebbd1b33f538e5a5583c48 | ||
refs/heads/master: 01461d7e65a6e3f92fd73ce4651e5f78a0a5990c |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
/* | ||
* SEGA Dreamcast controller driver | ||
* Based on drivers/usb/iforce.c | ||
* | ||
* Copyright Yaegashi Takeshi, 2001 | ||
* Adrian McMenamin, 2008 | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/slab.h> | ||
#include <linux/input.h> | ||
#include <linux/module.h> | ||
#include <linux/init.h> | ||
#include <linux/timer.h> | ||
#include <linux/maple.h> | ||
|
||
MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>"); | ||
MODULE_DESCRIPTION("SEGA Dreamcast controller driver"); | ||
MODULE_LICENSE("GPL"); | ||
|
||
struct dc_pad { | ||
struct input_dev *dev; | ||
struct maple_device *mdev; | ||
}; | ||
|
||
static void dc_pad_callback(struct mapleq *mq) | ||
{ | ||
unsigned short buttons; | ||
struct maple_device *mapledev = mq->dev; | ||
struct dc_pad *pad = maple_get_drvdata(mapledev); | ||
struct input_dev *dev = pad->dev; | ||
unsigned char *res = mq->recvbuf; | ||
|
||
buttons = ~le16_to_cpup((__le16 *)(res + 8)); | ||
|
||
input_report_abs(dev, ABS_HAT0Y, | ||
(buttons & 0x0010 ? -1 : 0) + (buttons & 0x0020 ? 1 : 0)); | ||
input_report_abs(dev, ABS_HAT0X, | ||
(buttons & 0x0040 ? -1 : 0) + (buttons & 0x0080 ? 1 : 0)); | ||
input_report_abs(dev, ABS_HAT1Y, | ||
(buttons & 0x1000 ? -1 : 0) + (buttons & 0x2000 ? 1 : 0)); | ||
input_report_abs(dev, ABS_HAT1X, | ||
(buttons & 0x4000 ? -1 : 0) + (buttons & 0x8000 ? 1 : 0)); | ||
|
||
input_report_key(dev, BTN_C, buttons & 0x0001); | ||
input_report_key(dev, BTN_B, buttons & 0x0002); | ||
input_report_key(dev, BTN_A, buttons & 0x0004); | ||
input_report_key(dev, BTN_START, buttons & 0x0008); | ||
input_report_key(dev, BTN_Z, buttons & 0x0100); | ||
input_report_key(dev, BTN_Y, buttons & 0x0200); | ||
input_report_key(dev, BTN_X, buttons & 0x0400); | ||
input_report_key(dev, BTN_SELECT, buttons & 0x0800); | ||
|
||
input_report_abs(dev, ABS_GAS, res[10]); | ||
input_report_abs(dev, ABS_BRAKE, res[11]); | ||
input_report_abs(dev, ABS_X, res[12]); | ||
input_report_abs(dev, ABS_Y, res[13]); | ||
input_report_abs(dev, ABS_RX, res[14]); | ||
input_report_abs(dev, ABS_RY, res[15]); | ||
} | ||
|
||
static int dc_pad_open(struct input_dev *dev) | ||
{ | ||
struct dc_pad *pad = dev->dev.platform_data; | ||
|
||
maple_getcond_callback(pad->mdev, dc_pad_callback, HZ/20, | ||
MAPLE_FUNC_CONTROLLER); | ||
|
||
return 0; | ||
} | ||
|
||
static void dc_pad_close(struct input_dev *dev) | ||
{ | ||
struct dc_pad *pad = dev->dev.platform_data; | ||
|
||
maple_getcond_callback(pad->mdev, dc_pad_callback, 0, | ||
MAPLE_FUNC_CONTROLLER); | ||
} | ||
|
||
/* allow the controller to be used */ | ||
static int __devinit probe_maple_controller(struct device *dev) | ||
{ | ||
static const short btn_bit[32] = { | ||
BTN_C, BTN_B, BTN_A, BTN_START, -1, -1, -1, -1, | ||
BTN_Z, BTN_Y, BTN_X, BTN_SELECT, -1, -1, -1, -1, | ||
-1, -1, -1, -1, -1, -1, -1, -1, | ||
-1, -1, -1, -1, -1, -1, -1, -1, | ||
}; | ||
|
||
static const short abs_bit[32] = { | ||
-1, -1, -1, -1, ABS_HAT0Y, ABS_HAT0Y, ABS_HAT0X, ABS_HAT0X, | ||
-1, -1, -1, -1, ABS_HAT1Y, ABS_HAT1Y, ABS_HAT1X, ABS_HAT1X, | ||
ABS_GAS, ABS_BRAKE, ABS_X, ABS_Y, ABS_RX, ABS_RY, -1, -1, | ||
-1, -1, -1, -1, -1, -1, -1, -1, | ||
}; | ||
|
||
struct maple_device *mdev = to_maple_dev(dev); | ||
struct maple_driver *mdrv = to_maple_driver(dev->driver); | ||
int i, error; | ||
struct dc_pad *pad; | ||
struct input_dev *idev; | ||
unsigned long data = be32_to_cpu(mdev->devinfo.function_data[0]); | ||
|
||
pad = kzalloc(sizeof(struct dc_pad), GFP_KERNEL); | ||
idev = input_allocate_device(); | ||
if (!pad || !idev) { | ||
error = -ENOMEM; | ||
goto fail; | ||
} | ||
|
||
pad->dev = idev; | ||
pad->mdev = mdev; | ||
|
||
idev->open = dc_pad_open; | ||
idev->close = dc_pad_close; | ||
|
||
for (i = 0; i < 32; i++) { | ||
if (data & (1 << i)) { | ||
if (btn_bit[i] >= 0) | ||
__set_bit(btn_bit[i], idev->keybit); | ||
else if (abs_bit[i] >= 0) | ||
__set_bit(abs_bit[i], idev->absbit); | ||
} | ||
} | ||
|
||
if (idev->keybit[BIT_WORD(BTN_JOYSTICK)]) | ||
idev->evbit[0] |= BIT_MASK(EV_KEY); | ||
|
||
if (idev->absbit[0]) | ||
idev->evbit[0] |= BIT_MASK(EV_ABS); | ||
|
||
for (i = ABS_X; i <= ABS_BRAKE; i++) | ||
input_set_abs_params(idev, i, 0, 255, 0, 0); | ||
|
||
for (i = ABS_HAT0X; i <= ABS_HAT3Y; i++) | ||
input_set_abs_params(idev, i, 1, -1, 0, 0); | ||
|
||
idev->dev.platform_data = pad; | ||
idev->dev.parent = &mdev->dev; | ||
idev->name = mdev->product_name; | ||
idev->id.bustype = BUS_HOST; | ||
input_set_drvdata(idev, pad); | ||
|
||
error = input_register_device(idev); | ||
if (error) | ||
goto fail; | ||
|
||
mdev->driver = mdrv; | ||
maple_set_drvdata(mdev, pad); | ||
|
||
return 0; | ||
|
||
fail: | ||
input_free_device(idev); | ||
kfree(pad); | ||
maple_set_drvdata(mdev, NULL); | ||
return error; | ||
} | ||
|
||
static int __devexit remove_maple_controller(struct device *dev) | ||
{ | ||
struct maple_device *mdev = to_maple_dev(dev); | ||
struct dc_pad *pad = maple_get_drvdata(mdev); | ||
|
||
mdev->callback = NULL; | ||
input_unregister_device(pad->dev); | ||
maple_set_drvdata(mdev, NULL); | ||
kfree(pad); | ||
|
||
return 0; | ||
} | ||
|
||
static struct maple_driver dc_pad_driver = { | ||
.function = MAPLE_FUNC_CONTROLLER, | ||
.drv = { | ||
.name = "Dreamcast_controller", | ||
.probe = probe_maple_controller, | ||
.remove = __devexit_p(remove_maple_controller), | ||
}, | ||
}; | ||
|
||
static int __init dc_pad_init(void) | ||
{ | ||
return maple_driver_register(&dc_pad_driver); | ||
} | ||
|
||
static void __exit dc_pad_exit(void) | ||
{ | ||
maple_driver_unregister(&dc_pad_driver); | ||
} | ||
|
||
module_init(dc_pad_init); | ||
module_exit(dc_pad_exit); |