initial import
[ps3linux_kernel_patches_314.git] / 0050-ps3sysmgr-char-device.patch
blobca5430d7768fe0183915613ed437c0901186e923
1 --- a/drivers/ps3/ps3-sys-manager.c 2012-01-26 20:35:02.242768746 +0100
2 +++ b/drivers/ps3/ps3-sys-manager.c 2012-01-26 20:38:07.325547265 +0100
3 @@ -3,6 +3,8 @@
5 * Copyright (C) 2007 Sony Computer Entertainment Inc.
6 * Copyright 2007 Sony Corp.
7 + * Copyright (C) 2011 graf_chokolo <grafchokolo@gmail.com>.
8 + * Copyright (C) 2011, 2012 glevand <geoffrey.levand@mail.ru>.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 @@ -22,7 +24,12 @@
13 #include <linux/module.h>
14 #include <linux/workqueue.h>
15 #include <linux/reboot.h>
16 +#include <linux/slab.h>
17 +#include <linux/uaccess.h>
18 +#include <linux/fs.h>
19 +#include <linux/miscdevice.h>
21 +#include <asm/atomic.h>
22 #include <asm/firmware.h>
23 #include <asm/lv1call.h>
24 #include <asm/ps3.h>
25 @@ -43,6 +50,14 @@
26 * specific payload.
29 +#define DEVICE_NAME "ps3sysmngr"
31 +static struct ps3sm {
32 + struct ps3_system_bus_device *dev;
33 + struct miscdevice misc;
34 + atomic_t misc_in_use;
35 +} *ps3sm;
37 /**
38 * struct ps3_sys_manager_header - System manager message header.
39 * @version: Header version, currently 1.
40 @@ -706,6 +721,86 @@
41 ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN);
44 +static int ps3_sys_manager_misc_open(struct inode *inode, struct file *file)
46 + if (atomic_inc_return(&ps3sm->misc_in_use) == 1)
47 + ps3_vuart_cancel_async(ps3sm->dev);
49 + return 0;
52 +static int ps3_sys_manager_misc_release(struct inode *inode, struct file *file)
54 + if (atomic_dec_and_test(&ps3sm->misc_in_use))
55 + ps3_vuart_read_async(ps3sm->dev, PS3_SM_RX_MSG_LEN_MIN);
57 + return 0;
60 +static ssize_t ps3_sys_manager_misc_read(struct file *file, char __user *usrbuf,
61 + size_t count, loff_t *pos)
63 + char *buf;
64 + int result;
66 + buf = kmalloc(count, GFP_KERNEL);
67 + if (!buf)
68 + return -ENOMEM;
70 + result = ps3_vuart_read(ps3sm->dev, buf, count);
71 + if (result)
72 + goto out;
74 + if (copy_to_user(usrbuf, buf, count)) {
75 + result = -EFAULT;
76 + goto out;
77 + }
79 + result = count;
81 +out:
83 + kfree(buf);
85 + return result;
88 +static ssize_t ps3_sys_manager_misc_write(struct file *file, const char __user *usrbuf,
89 + size_t count, loff_t *pos)
91 + char *buf;
92 + int result;
94 + buf = kmalloc(count, GFP_KERNEL);
95 + if (!buf)
96 + return -ENOMEM;
98 + if (copy_from_user(buf, usrbuf, count)) {
99 + result = -EFAULT;
100 + goto out;
103 + result = ps3_vuart_write(ps3sm->dev, buf, count);
104 + if (result)
105 + goto out;
107 + result = count;
109 +out:
111 + kfree(buf);
113 + return result;
116 +static const struct file_operations ps3_sys_manager_misc_fops = {
117 + .owner = THIS_MODULE,
118 + .open = ps3_sys_manager_misc_open,
119 + .release = ps3_sys_manager_misc_release,
120 + .read = ps3_sys_manager_misc_read,
121 + .write = ps3_sys_manager_misc_write,
124 static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev)
126 int result;
127 @@ -727,12 +822,47 @@
128 result = ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN);
129 BUG_ON(result);
131 + ps3sm = kzalloc(sizeof(*ps3sm), GFP_KERNEL);
132 + if (!ps3sm)
133 + goto skip_misc;
135 + ps3sm->dev = dev;
137 + ps3sm->misc.parent = &dev->core;
138 + ps3sm->misc.minor = MISC_DYNAMIC_MINOR,
139 + ps3sm->misc.name = DEVICE_NAME,
140 + ps3sm->misc.fops = &ps3_sys_manager_misc_fops,
141 + atomic_set(&ps3sm->misc_in_use, 0);
143 + result = misc_register(&ps3sm->misc);
144 + if (result) {
145 + dev_err(&dev->core, "%s:%u: misc_register failed %d\n",
146 + __func__, __LINE__, result);
147 + kfree(ps3sm);
148 + ps3sm = NULL;
149 + goto skip_misc;
152 + dev_info(&dev->core, "%s:%u: registered misc device %d\n",
153 + __func__, __LINE__, ps3sm->misc.minor);
155 +skip_misc:
157 + result = 0;
159 return result;
162 static int ps3_sys_manager_remove(struct ps3_system_bus_device *dev)
164 dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
166 + if (ps3sm) {
167 + misc_deregister(&ps3sm->misc);
168 + kfree(ps3sm);
169 + ps3sm = NULL;
172 return 0;