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
5 PS3_MATCH_ID_STOR_NOR_FLASH = 12,
6 PS3_MATCH_ID_DISP_MANAGER = 13,
7 + PS3_MATCH_ID_STOR_ENCDEC = 14,
10 enum ps3_match_sub_id {
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
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
35 + case PS3_DEV_TYPE_STOR_ENCDEC:
36 + result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_ENCDEC);
38 + pr_debug("%s:%u ps3_setup_storage_dev failed\n",
39 + __func__, __LINE__);
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
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:
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
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;
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
80 This driver allows you to create/delete/modify regions
81 on PS3 storage devices.
84 + tristate "PS3 ENCDEC Driver"
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.
94 bool "PS3 udbg output via UDP broadcasts on Ethernet"
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
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
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.
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;
157 + wait_queue_head_t read_wq;
158 + wait_queue_head_t write_wq;
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;
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)
179 + DEFINE_WAIT(__wait);
182 + prepare_to_wait(&priv->read_wq, &__wait, TASK_INTERRUPTIBLE);
184 + if (priv->cmd_data_avail)
187 + mutex_unlock(&priv->mtx);
189 + if (signal_pending(current)) {
190 + finish_wait(&priv->read_wq, &__wait);
191 + return (-ERESTARTSYS);
196 + res = mutex_lock_interruptible(&priv->mtx);
198 + finish_wait(&priv->read_wq, &__wait);
203 + finish_wait(&priv->read_wq, &__wait);
209 + if (count > BOUNCE_SIZE)
210 + count = BOUNCE_SIZE;
212 + if (!count || (priv->cmd_done && priv->cmd_failed))
215 + if (copy_to_user(usrbuf, priv->bounce_rbuf + *pos, count)) {
220 + priv->cmd_data_avail = 0;
226 + mutex_unlock(&priv->mtx);
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;
239 + if (mutex_lock_interruptible(&priv->mtx))
240 + return (-ERESTARTSYS);
242 + if (file->f_flags & O_NONBLOCK) {
243 + if (!priv->cmd_done)
246 + DEFINE_WAIT(__wait);
249 + prepare_to_wait(&priv->write_wq, &__wait, TASK_INTERRUPTIBLE);
251 + if (priv->cmd_done)
254 + mutex_unlock(&priv->mtx);
256 + if (signal_pending(current)) {
257 + finish_wait(&priv->write_wq, &__wait);
258 + return (-ERESTARTSYS);
263 + res = mutex_lock_interruptible(&priv->mtx);
265 + finish_wait(&priv->write_wq, &__wait);
270 + finish_wait(&priv->write_wq, &__wait);
276 + if (count > BOUNCE_SIZE + sizeof(cmd))
277 + count = BOUNCE_SIZE + sizeof(cmd);
282 + if (count < sizeof(cmd)) {
287 + if (copy_from_user(&cmd, usrbuf, sizeof(cmd))) {
292 + if (copy_from_user(priv->bounce_wbuf, usrbuf + sizeof(cmd), count - sizeof(cmd))) {
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);
305 + dev_err(&dev->sbd.core, "%s:%u: res=%d\n",
306 + __func__, __LINE__, res);
307 + priv->cmd_done = 1;
316 + mutex_unlock(&priv->mtx);
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);
342 +static irqreturn_t ps3encdec_interrupt(int irq, void *data)
344 + struct ps3_storage_device *dev = data;
345 + struct ps3encdec_private *priv;
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);
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;
391 + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
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) {
401 + goto fail_free_priv;
404 + res = ps3stor_setup(dev, ps3encdec_interrupt);
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);
423 + goto fail_teardown;
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;
437 + ps3stor_teardown(dev);
441 + kfree(dev->bounce_buf);
446 + ps3_system_bus_set_drvdata(_dev, NULL);
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);
462 + ps3_system_bus_set_drvdata(_dev, NULL);
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)
480 + if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
483 + res = ps3_system_bus_driver_register(&ps3encdec);
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);