initial import
[ps3linux_kernel_patches_314.git] / 0210-ps3encdec.patch
blob6944c46694539b552ab795e97481a8f1a0e7f3ce
1 --- a/arch/powerpc/include/asm/ps3.h 2012-08-02 23:17:17.126972935 +0200
2 +++ b/arch/powerpc/include/asm/ps3.h 2012-08-06 19:41:56.754901977 +0200
3 @@ -328,6 +328,7 @@
4 PS3_MATCH_ID_LPM = 11,
5 PS3_MATCH_ID_STOR_NOR_FLASH = 12,
6 PS3_MATCH_ID_DISP_MANAGER = 13,
7 + PS3_MATCH_ID_STOR_ENCDEC = 14,
8 };
10 enum ps3_match_sub_id {
11 @@ -349,6 +350,7 @@
12 #define PS3_MODULE_ALIAS_LPM "ps3:11:0"
13 #define PS3_MODULE_ALIAS_STOR_NOR_FLASH "ps3:12:0"
14 #define PS3_MODULE_ALIAS_DISP_MANAGER "ps3:13:0"
15 +#define PS3_MODULE_ALIAS_STOR_ENCDEC "ps3:14:0"
17 enum ps3_system_bus_device_type {
18 PS3_DEVICE_TYPE_IOC0 = 1,
19 --- a/arch/powerpc/platforms/ps3/platform.h 2012-08-02 23:17:17.110306267 +0200
20 +++ b/arch/powerpc/platforms/ps3/platform.h 2012-08-06 19:42:30.948237298 +0200
21 @@ -89,6 +89,7 @@
22 PS3_DEV_TYPE_SB_GPIO = 6,
23 PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */
24 PS3_DEV_TYPE_STOR_NOR_FLASH = 254,
25 + PS3_DEV_TYPE_STOR_ENCDEC = 255,
28 int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
29 --- a/arch/powerpc/platforms/ps3/device-init.c 2012-08-02 23:17:17.130306269 +0200
30 +++ b/arch/powerpc/platforms/ps3/device-init.c 2012-08-06 19:43:12.538239719 +0200
31 @@ -621,6 +621,13 @@
32 __func__, __LINE__);
33 break;
35 + case PS3_DEV_TYPE_STOR_ENCDEC:
36 + result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_ENCDEC);
37 + if (result)
38 + pr_debug("%s:%u ps3_setup_storage_dev failed\n",
39 + __func__, __LINE__);
40 + break;
42 default:
43 result = 0;
44 pr_debug("%s:%u: unsupported dev_type %u\n", __func__, __LINE__,
45 --- a/arch/powerpc/platforms/ps3/system-bus.c 2012-08-02 23:17:17.126972935 +0200
46 +++ b/arch/powerpc/platforms/ps3/system-bus.c 2012-08-06 19:44:03.851576042 +0200
47 @@ -175,6 +175,7 @@
48 case PS3_MATCH_ID_STOR_ROM:
49 case PS3_MATCH_ID_STOR_FLASH:
50 case PS3_MATCH_ID_STOR_NOR_FLASH:
51 + case PS3_MATCH_ID_STOR_ENCDEC:
52 return ps3_open_hv_device_sb(dev);
54 case PS3_MATCH_ID_SOUND:
55 @@ -215,6 +216,7 @@
56 case PS3_MATCH_ID_STOR_ROM:
57 case PS3_MATCH_ID_STOR_FLASH:
58 case PS3_MATCH_ID_STOR_NOR_FLASH:
59 + case PS3_MATCH_ID_STOR_ENCDEC:
60 return ps3_close_hv_device_sb(dev);
62 case PS3_MATCH_ID_SOUND:
63 --- a/drivers/ps3/ps3stor_lib.c 2012-08-02 23:17:17.100306267 +0200
64 +++ b/drivers/ps3/ps3stor_lib.c 2012-08-06 20:43:55.981785017 +0200
65 @@ -90,8 +90,9 @@
66 unsigned int i;
67 unsigned long n;
69 - if (dev->sbd.match_id == PS3_MATCH_ID_STOR_ROM) {
70 - /* special case: CD-ROM is assumed always accessible */
71 + if ((dev->sbd.match_id == PS3_MATCH_ID_STOR_ROM) ||
72 + (dev->sbd.match_id == PS3_MATCH_ID_STOR_ENCDEC)) {
73 + /* special case: CD-ROM and ENCDEC are assumed always accessible */
74 dev->accessible_regions = 1;
75 return 0;
77 --- a/arch/powerpc/platforms/ps3/Kconfig 2012-08-02 23:17:17.153639603 +0200
78 +++ b/arch/powerpc/platforms/ps3/Kconfig 2012-08-06 19:46:13.304916903 +0200
79 @@ -192,6 +192,16 @@
80 This driver allows you to create/delete/modify regions
81 on PS3 storage devices.
83 +config PS3_ENCDEC
84 + tristate "PS3 ENCDEC Driver"
85 + depends on PPC_PS3
86 + select PS3_STORAGE
87 + help
88 + Include support for the PS3 ENCDEC device.
90 + This support is required to access the PS3 ENCDEC device.
91 + In general, all users will say Y or M.
93 config PS3GELIC_UDBG
94 bool "PS3 udbg output via UDP broadcasts on Ethernet"
95 depends on PPC_PS3
96 --- a/drivers/char/Makefile 2012-08-02 23:17:17.153639603 +0200
97 +++ b/drivers/char/Makefile 2012-08-06 19:47:18.001587333 +0200
98 @@ -67,3 +67,4 @@
100 obj-$(CONFIG_PS3_PHYSMEM) += ps3physmem.o
101 obj-$(CONFIG_PS3_STRGMNGR) += ps3strgmngr.o
102 +obj-$(CONFIG_PS3_ENCDEC) += ps3encdec.o
103 --- /dev/null 2012-08-07 02:54:53.492474007 +0200
104 +++ b/drivers/char/ps3encdec.c 2012-08-07 02:56:38.822480157 +0200
105 @@ -0,0 +1,394 @@
107 + * PS3 ENCDEC Driver
109 + * Copyright (C) 2011 graf_chokolo <grafchokolo@gmail.com>
110 + * Copyright (C) 2011, 2012 glevand <geoffrey.levand@mail.ru>
111 + * All rights reserved.
113 + * This program is free software; you can redistribute it and/or modify it
114 + * under the terms of the GNU General Public License as published
115 + * by the Free Software Foundation; version 2 of the License.
117 + * This program is distributed in the hope that it will be useful, but
118 + * WITHOUT ANY WARRANTY; without even the implied warranty of
119 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
120 + * General Public License for more details.
122 + * You should have received a copy of the GNU General Public License along
123 + * with this program; if not, write to the Free Software Foundation, Inc.,
124 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
125 + */
127 +#include <linux/module.h>
128 +#include <linux/kernel.h>
129 +#include <linux/init.h>
130 +#include <linux/slab.h>
131 +#include <linux/fs.h>
132 +#include <linux/sched.h>
133 +#include <linux/mutex.h>
134 +#include <linux/poll.h>
135 +#include <linux/uaccess.h>
136 +#include <linux/compat.h>
137 +#include <linux/miscdevice.h>
139 +#include <asm/ps3.h>
140 +#include <asm/lv1call.h>
141 +#include <asm/ps3stor.h>
142 +#include <asm/firmware.h>
144 +#define DEVICE_NAME "ps3encdec"
146 +#define BOUNCE_SIZE (4 * 1024)
148 +struct ps3encdec_private
150 + struct ps3_storage_device *dev;
151 + struct miscdevice misc;
152 + char *bounce_wbuf;
153 + u64 bounce_wlpar;
154 + char *bounce_rbuf;
155 + u64 bounce_rlpar;
156 + struct mutex mtx;
157 + wait_queue_head_t read_wq;
158 + wait_queue_head_t write_wq;
159 + int cmd_done;
160 + int cmd_failed;
161 + int cmd_data_avail;
164 +static struct ps3encdec_private *ps3encdec_priv;
166 +static ssize_t ps3encdec_read(struct file *file, char __user *usrbuf,
167 + size_t count, loff_t *pos)
169 + struct ps3encdec_private *priv = ps3encdec_priv;
170 + int res = 0;
172 + if (mutex_lock_interruptible(&priv->mtx))
173 + return (-ERESTARTSYS);
175 + if (file->f_flags & O_NONBLOCK) {
176 + if (!priv->cmd_done || priv->cmd_failed)
177 + res = -EAGAIN;
178 + } else {
179 + DEFINE_WAIT(__wait);
181 + while (1) {
182 + prepare_to_wait(&priv->read_wq, &__wait, TASK_INTERRUPTIBLE);
184 + if (priv->cmd_data_avail)
185 + break;
187 + mutex_unlock(&priv->mtx);
189 + if (signal_pending(current)) {
190 + finish_wait(&priv->read_wq, &__wait);
191 + return (-ERESTARTSYS);
194 + schedule();
196 + res = mutex_lock_interruptible(&priv->mtx);
197 + if (res) {
198 + finish_wait(&priv->read_wq, &__wait);
199 + return (res);
203 + finish_wait(&priv->read_wq, &__wait);
206 + if (res)
207 + goto done;
209 + if (count > BOUNCE_SIZE)
210 + count = BOUNCE_SIZE;
212 + if (!count || (priv->cmd_done && priv->cmd_failed))
213 + goto done;
215 + if (copy_to_user(usrbuf, priv->bounce_rbuf + *pos, count)) {
216 + res = -EFAULT;
217 + goto done;
220 + priv->cmd_data_avail = 0;
222 + res = count;
224 +done:
226 + mutex_unlock(&priv->mtx);
228 + return (res);
231 +static ssize_t ps3encdec_write(struct file *file, const char __user *usrbuf,
232 + size_t count, loff_t *pos)
234 + struct ps3encdec_private *priv = ps3encdec_priv;
235 + struct ps3_storage_device *dev = priv->dev;
236 + u32 cmd;
237 + int res = 0;
239 + if (mutex_lock_interruptible(&priv->mtx))
240 + return (-ERESTARTSYS);
242 + if (file->f_flags & O_NONBLOCK) {
243 + if (!priv->cmd_done)
244 + res = -EAGAIN;
245 + } else {
246 + DEFINE_WAIT(__wait);
248 + while (1) {
249 + prepare_to_wait(&priv->write_wq, &__wait, TASK_INTERRUPTIBLE);
251 + if (priv->cmd_done)
252 + break;
254 + mutex_unlock(&priv->mtx);
256 + if (signal_pending(current)) {
257 + finish_wait(&priv->write_wq, &__wait);
258 + return (-ERESTARTSYS);
261 + schedule();
263 + res = mutex_lock_interruptible(&priv->mtx);
264 + if (res) {
265 + finish_wait(&priv->write_wq, &__wait);
266 + return (res);
270 + finish_wait(&priv->write_wq, &__wait);
273 + if (res)
274 + goto done;
276 + if (count > BOUNCE_SIZE + sizeof(cmd))
277 + count = BOUNCE_SIZE + sizeof(cmd);
279 + if (!count)
280 + goto done;
282 + if (count < sizeof(cmd)) {
283 + res = -EINVAL;
284 + goto done;
287 + if (copy_from_user(&cmd, usrbuf, sizeof(cmd))) {
288 + res = -EFAULT;
289 + goto done;
292 + if (copy_from_user(priv->bounce_wbuf, usrbuf + sizeof(cmd), count - sizeof(cmd))) {
293 + res = -EFAULT;
294 + goto done;
297 + priv->cmd_done = 0;
298 + priv->cmd_failed = 1;
299 + priv->cmd_data_avail = 0;
301 + res = lv1_storage_send_device_command(dev->sbd.dev_id, cmd,
302 + priv->bounce_wlpar, count - sizeof(cmd),
303 + priv->bounce_rlpar, BOUNCE_SIZE, &dev->tag);
304 + if (res) {
305 + dev_err(&dev->sbd.core, "%s:%u: res=%d\n",
306 + __func__, __LINE__, res);
307 + priv->cmd_done = 1;
308 + res = -EIO;
309 + goto done;
312 + res = count;
314 +done:
316 + mutex_unlock(&priv->mtx);
318 + return (res);
321 +static unsigned int ps3encdec_poll(struct file *file, poll_table *wait)
323 + struct ps3encdec_private *priv = ps3encdec_priv;
324 + unsigned int mask = 0;
326 + mutex_lock(&priv->mtx);
328 + poll_wait(file, &priv->read_wq, wait);
329 + poll_wait(file, &priv->write_wq, wait);
331 + if (priv->cmd_data_avail)
332 + mask |= POLLIN | POLLRDNORM;
334 + if (priv->cmd_done)
335 + mask |= POLLOUT | POLLWRNORM;
337 + mutex_unlock(&priv->mtx);
339 + return (mask);
342 +static irqreturn_t ps3encdec_interrupt(int irq, void *data)
344 + struct ps3_storage_device *dev = data;
345 + struct ps3encdec_private *priv;
346 + u64 tag, status;
347 + int res;
349 + res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
351 + pr_info("%s:%d: res=%d status=%llx\n", __func__, __LINE__, res, status);
353 + if (tag != dev->tag) {
354 + dev_err(&dev->sbd.core,
355 + "%s:%u: tag mismatch, got %llx, expected %llx\n",
356 + __func__, __LINE__, tag, dev->tag);
359 + if (res) {
360 + dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx\n",
361 + __func__, __LINE__, res, status);
362 + return (IRQ_HANDLED);
365 + priv = ps3_system_bus_get_drvdata(&dev->sbd);
367 + priv->cmd_done = 1;
368 + priv->cmd_failed = (status != 0);
369 + priv->cmd_data_avail = !priv->cmd_failed;
371 + wake_up_interruptible(&priv->read_wq);
372 + wake_up_interruptible(&priv->write_wq);
374 + return (IRQ_HANDLED);
377 +static const struct file_operations ps3encdec_fops = {
378 + .owner = THIS_MODULE,
379 + .open = nonseekable_open,
380 + .read = ps3encdec_read,
381 + .write = ps3encdec_write,
382 + .poll = ps3encdec_poll,
385 +static int ps3encdec_probe(struct ps3_system_bus_device *_dev)
387 + struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
388 + struct ps3encdec_private *priv;
389 + int res;
391 + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
392 + if (!priv)
393 + return (-ENOMEM);
395 + ps3_system_bus_set_drvdata(_dev, priv);
397 + dev->bounce_size = BOUNCE_SIZE * 2;
398 + dev->bounce_buf = kmalloc(dev->bounce_size, GFP_DMA);
399 + if (!dev->bounce_buf) {
400 + res = -ENOMEM;
401 + goto fail_free_priv;
404 + res = ps3stor_setup(dev, ps3encdec_interrupt);
405 + if (res)
406 + goto fail_free_bounce;
408 + mutex_init(&priv->mtx);
410 + init_waitqueue_head(&priv->read_wq);
411 + init_waitqueue_head(&priv->write_wq);
413 + priv->cmd_done = 1;
414 + priv->cmd_failed = 0;
415 + priv->cmd_data_avail = 0;
417 + priv->misc.minor = MISC_DYNAMIC_MINOR,
418 + priv->misc.name = DEVICE_NAME,
419 + priv->misc.fops = &ps3encdec_fops,
421 + res = misc_register(&priv->misc);
422 + if (res)
423 + goto fail_teardown;
425 + priv->dev = dev;
426 + priv->bounce_wbuf = dev->bounce_buf;
427 + priv->bounce_wlpar = dev->bounce_lpar;
428 + priv->bounce_rbuf = dev->bounce_buf + BOUNCE_SIZE;
429 + priv->bounce_rlpar = dev->bounce_lpar + BOUNCE_SIZE;
431 + ps3encdec_priv = priv;
433 + return (0);
435 +fail_teardown:
437 + ps3stor_teardown(dev);
439 +fail_free_bounce:
441 + kfree(dev->bounce_buf);
443 +fail_free_priv:
445 + kfree(priv);
446 + ps3_system_bus_set_drvdata(_dev, NULL);
448 + return (res);
451 +static int ps3encdec_remove(struct ps3_system_bus_device *_dev)
453 + struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
454 + struct ps3encdec_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
456 + ps3encdec_priv = NULL;
458 + misc_deregister(&priv->misc);
459 + ps3stor_teardown(dev);
460 + kfree(dev->bounce_buf);
461 + kfree(priv);
462 + ps3_system_bus_set_drvdata(_dev, NULL);
464 + return (0);
467 +static struct ps3_system_bus_driver ps3encdec = {
468 + .match_id = PS3_MATCH_ID_STOR_ENCDEC,
469 + .core.name = DEVICE_NAME,
470 + .core.owner = THIS_MODULE,
471 + .probe = ps3encdec_probe,
472 + .remove = ps3encdec_remove,
473 + .shutdown = ps3encdec_remove,
476 +static int __init ps3encdec_init(void)
478 + int res;
480 + if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
481 + return (-ENODEV);
483 + res = ps3_system_bus_driver_register(&ps3encdec);
485 + return (res);
488 +static void __exit ps3encdec_exit(void)
490 + ps3_system_bus_driver_unregister(&ps3encdec);
493 +module_init(ps3encdec_init);
494 +module_exit(ps3encdec_exit);
496 +MODULE_AUTHOR("glevand");
497 +MODULE_DESCRIPTION("PS3 ENCDEC Driver");
498 +MODULE_LICENSE("GPL");
499 +MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_ENCDEC);