diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/viodasd.c | 4 | ||||
-rw-r--r-- | drivers/char/briq_panel.c | 10 | ||||
-rw-r--r-- | drivers/char/hvc_console.c | 2 | ||||
-rw-r--r-- | drivers/char/viotape.c | 12 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpadlpar_core.c | 6 | ||||
-rw-r--r-- | drivers/pcmcia/Kconfig | 17 | ||||
-rw-r--r-- | drivers/pcmcia/m8xx_pcmcia.c | 351 | ||||
-rw-r--r-- | drivers/ps3/Makefile | 5 | ||||
-rw-r--r-- | drivers/ps3/ps3av.c | 372 | ||||
-rw-r--r-- | drivers/ps3/ps3av_cmd.c | 51 | ||||
-rw-r--r-- | drivers/ps3/ps3stor_lib.c | 302 | ||||
-rw-r--r-- | drivers/ps3/sys-manager-core.c | 68 | ||||
-rw-r--r-- | drivers/ps3/sys-manager.c | 290 | ||||
-rw-r--r-- | drivers/ps3/vuart.c | 817 | ||||
-rw-r--r-- | drivers/ps3/vuart.h | 71 | ||||
-rw-r--r-- | drivers/rtc/Kconfig | 2 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_core.c | 2 | ||||
-rw-r--r-- | drivers/serial/of_serial.c | 33 | ||||
-rw-r--r-- | drivers/video/Kconfig | 4 | ||||
-rw-r--r-- | drivers/video/ps3fb.c | 290 |
20 files changed, 1638 insertions, 1071 deletions
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index 68592c336011..dae39911a11d 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c | |||
@@ -252,10 +252,10 @@ static int viodasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) | |||
252 | struct gendisk *disk = bdev->bd_disk; | 252 | struct gendisk *disk = bdev->bd_disk; |
253 | struct viodasd_device *d = disk->private_data; | 253 | struct viodasd_device *d = disk->private_data; |
254 | 254 | ||
255 | geo->sectors = d->sectors ? d->sectors : 0; | 255 | geo->sectors = d->sectors ? d->sectors : 32; |
256 | geo->heads = d->tracks ? d->tracks : 64; | 256 | geo->heads = d->tracks ? d->tracks : 64; |
257 | geo->cylinders = d->cylinders ? d->cylinders : | 257 | geo->cylinders = d->cylinders ? d->cylinders : |
258 | get_capacity(disk) / (geo->cylinders * geo->heads); | 258 | get_capacity(disk) / (geo->sectors * geo->heads); |
259 | 259 | ||
260 | return 0; | 260 | return 0; |
261 | } | 261 | } |
diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c index ed53f541d9e8..b6f2639f903d 100644 --- a/drivers/char/briq_panel.c +++ b/drivers/char/briq_panel.c | |||
@@ -91,11 +91,6 @@ static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count | |||
91 | unsigned short c; | 91 | unsigned short c; |
92 | unsigned char cp; | 92 | unsigned char cp; |
93 | 93 | ||
94 | #if 0 /* Can't seek (pread) on this device */ | ||
95 | if (ppos != &file->f_pos) | ||
96 | return -ESPIPE; | ||
97 | #endif | ||
98 | |||
99 | if (!vfd_is_open) | 94 | if (!vfd_is_open) |
100 | return -ENODEV; | 95 | return -ENODEV; |
101 | 96 | ||
@@ -139,11 +134,6 @@ static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_ | |||
139 | size_t indx = len; | 134 | size_t indx = len; |
140 | int i, esc = 0; | 135 | int i, esc = 0; |
141 | 136 | ||
142 | #if 0 /* Can't seek (pwrite) on this device */ | ||
143 | if (ppos != &file->f_pos) | ||
144 | return -ESPIPE; | ||
145 | #endif | ||
146 | |||
147 | if (!vfd_is_open) | 137 | if (!vfd_is_open) |
148 | return -EBUSY; | 138 | return -EBUSY; |
149 | 139 | ||
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 322bc5f7d86b..b3ab42e0dd4a 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c | |||
@@ -674,7 +674,7 @@ static const cpumask_t cpus_in_xmon = CPU_MASK_NONE; | |||
674 | * calling hvc_poll() who determines whether a console adapter support | 674 | * calling hvc_poll() who determines whether a console adapter support |
675 | * interrupts. | 675 | * interrupts. |
676 | */ | 676 | */ |
677 | int khvcd(void *unused) | 677 | static int khvcd(void *unused) |
678 | { | 678 | { |
679 | int poll_mask; | 679 | int poll_mask; |
680 | struct hvc_struct *hp; | 680 | struct hvc_struct *hp; |
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index 13faf8d17482..db57277117bb 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c | |||
@@ -873,12 +873,12 @@ free_op: | |||
873 | } | 873 | } |
874 | 874 | ||
875 | const struct file_operations viotap_fops = { | 875 | const struct file_operations viotap_fops = { |
876 | owner: THIS_MODULE, | 876 | .owner = THIS_MODULE, |
877 | read: viotap_read, | 877 | .read = viotap_read, |
878 | write: viotap_write, | 878 | .write = viotap_write, |
879 | ioctl: viotap_ioctl, | 879 | .ioctl = viotap_ioctl, |
880 | open: viotap_open, | 880 | .open = viotap_open, |
881 | release: viotap_release, | 881 | .release = viotap_release, |
882 | }; | 882 | }; |
883 | 883 | ||
884 | /* Handle interrupt events for tape */ | 884 | /* Handle interrupt events for tape */ |
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index bb3c101c2c5a..deb6b5e35feb 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c | |||
@@ -159,8 +159,8 @@ static void dlpar_pci_add_bus(struct device_node *dn) | |||
159 | /* Claim new bus resources */ | 159 | /* Claim new bus resources */ |
160 | pcibios_claim_one_bus(dev->bus); | 160 | pcibios_claim_one_bus(dev->bus); |
161 | 161 | ||
162 | /* ioremap() for child bus, which may or may not succeed */ | 162 | /* Map IO space for child bus, which may or may not succeed */ |
163 | remap_bus_range(dev->subordinate); | 163 | pcibios_map_io_space(dev->subordinate); |
164 | 164 | ||
165 | /* Add new devices to global lists. Register in proc, sysfs. */ | 165 | /* Add new devices to global lists. Register in proc, sysfs. */ |
166 | pci_bus_add_devices(phb->bus); | 166 | pci_bus_add_devices(phb->bus); |
@@ -390,7 +390,7 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn) | |||
390 | } else | 390 | } else |
391 | pcibios_remove_pci_devices(bus); | 391 | pcibios_remove_pci_devices(bus); |
392 | 392 | ||
393 | if (unmap_bus_range(bus)) { | 393 | if (pcibios_unmap_io_space(bus)) { |
394 | printk(KERN_ERR "%s: failed to unmap bus range\n", | 394 | printk(KERN_ERR "%s: failed to unmap bus range\n", |
395 | __FUNCTION__); | 395 | __FUNCTION__); |
396 | return -ERANGE; | 396 | return -ERANGE; |
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 35f88649d3b7..c0c77f82d051 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig | |||
@@ -180,14 +180,15 @@ config TCIC | |||
180 | PCMCIA cards are plugged into. If unsure, say N. | 180 | PCMCIA cards are plugged into. If unsure, say N. |
181 | 181 | ||
182 | config PCMCIA_M8XX | 182 | config PCMCIA_M8XX |
183 | tristate "MPC8xx PCMCIA support" | 183 | tristate "MPC8xx PCMCIA support" |
184 | depends on PCMCIA && PPC && 8xx | 184 | depends on PCMCIA && PPC && 8xx |
185 | select PCCARD_IODYN | 185 | select PCCARD_IODYN |
186 | help | 186 | select PCCARD_NONSTATIC |
187 | Say Y here to include support for PowerPC 8xx series PCMCIA | 187 | help |
188 | controller. | 188 | Say Y here to include support for PowerPC 8xx series PCMCIA |
189 | 189 | controller. | |
190 | This driver is also available as a module called m8xx_pcmcia. | 190 | |
191 | This driver is also available as a module called m8xx_pcmcia. | ||
191 | 192 | ||
192 | config HD64465_PCMCIA | 193 | config HD64465_PCMCIA |
193 | tristate "HD64465 host bridge support" | 194 | tristate "HD64465 host bridge support" |
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index 9721ed7bf502..3b40f9623cc9 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c | |||
@@ -10,7 +10,7 @@ | |||
10 | * Further fixes, v2.6 kernel port | 10 | * Further fixes, v2.6 kernel port |
11 | * <marcelo.tosatti@cyclades.com> | 11 | * <marcelo.tosatti@cyclades.com> |
12 | * | 12 | * |
13 | * Some fixes, additions (C) 2005 Montavista Software, Inc. | 13 | * Some fixes, additions (C) 2005-2007 Montavista Software, Inc. |
14 | * <vbordug@ru.mvista.com> | 14 | * <vbordug@ru.mvista.com> |
15 | * | 15 | * |
16 | * "The ExCA standard specifies that socket controllers should provide | 16 | * "The ExCA standard specifies that socket controllers should provide |
@@ -40,10 +40,6 @@ | |||
40 | #include <linux/fcntl.h> | 40 | #include <linux/fcntl.h> |
41 | #include <linux/string.h> | 41 | #include <linux/string.h> |
42 | 42 | ||
43 | #include <asm/io.h> | ||
44 | #include <asm/bitops.h> | ||
45 | #include <asm/system.h> | ||
46 | |||
47 | #include <linux/kernel.h> | 43 | #include <linux/kernel.h> |
48 | #include <linux/errno.h> | 44 | #include <linux/errno.h> |
49 | #include <linux/slab.h> | 45 | #include <linux/slab.h> |
@@ -51,11 +47,18 @@ | |||
51 | #include <linux/ioport.h> | 47 | #include <linux/ioport.h> |
52 | #include <linux/delay.h> | 48 | #include <linux/delay.h> |
53 | #include <linux/interrupt.h> | 49 | #include <linux/interrupt.h> |
54 | #include <linux/platform_device.h> | 50 | #include <linux/fsl_devices.h> |
55 | 51 | ||
52 | #include <asm/io.h> | ||
53 | #include <asm/bitops.h> | ||
54 | #include <asm/system.h> | ||
55 | #include <asm/time.h> | ||
56 | #include <asm/mpc8xx.h> | 56 | #include <asm/mpc8xx.h> |
57 | #include <asm/8xx_immap.h> | 57 | #include <asm/8xx_immap.h> |
58 | #include <asm/irq.h> | 58 | #include <asm/irq.h> |
59 | #include <asm/fs_pd.h> | ||
60 | #include <asm/of_device.h> | ||
61 | #include <asm/of_platform.h> | ||
59 | 62 | ||
60 | #include <pcmcia/version.h> | 63 | #include <pcmcia/version.h> |
61 | #include <pcmcia/cs_types.h> | 64 | #include <pcmcia/cs_types.h> |
@@ -146,27 +149,17 @@ MODULE_LICENSE("Dual MPL/GPL"); | |||
146 | #define PCMCIA_MEM_WIN_BASE 0xe0000000 /* base address for memory window 0 */ | 149 | #define PCMCIA_MEM_WIN_BASE 0xe0000000 /* base address for memory window 0 */ |
147 | #define PCMCIA_MEM_WIN_SIZE 0x04000000 /* each memory window is 64 MByte */ | 150 | #define PCMCIA_MEM_WIN_SIZE 0x04000000 /* each memory window is 64 MByte */ |
148 | #define PCMCIA_IO_WIN_BASE _IO_BASE /* base address for io window 0 */ | 151 | #define PCMCIA_IO_WIN_BASE _IO_BASE /* base address for io window 0 */ |
149 | |||
150 | #define PCMCIA_SCHLVL PCMCIA_INTERRUPT /* Status Change Interrupt Level */ | ||
151 | |||
152 | /* ------------------------------------------------------------------------- */ | 152 | /* ------------------------------------------------------------------------- */ |
153 | 153 | ||
154 | /* 2.4.x and newer has this always in HZ */ | 154 | static int pcmcia_schlvl; |
155 | #define M8XX_BUSFREQ ((((bd_t *)&(__res))->bi_busfreq)) | ||
156 | |||
157 | static int pcmcia_schlvl = PCMCIA_SCHLVL; | ||
158 | 155 | ||
159 | static DEFINE_SPINLOCK(events_lock); | 156 | static DEFINE_SPINLOCK(events_lock); |
160 | 157 | ||
161 | |||
162 | #define PCMCIA_SOCKET_KEY_5V 1 | 158 | #define PCMCIA_SOCKET_KEY_5V 1 |
163 | #define PCMCIA_SOCKET_KEY_LV 2 | 159 | #define PCMCIA_SOCKET_KEY_LV 2 |
164 | 160 | ||
165 | /* look up table for pgcrx registers */ | 161 | /* look up table for pgcrx registers */ |
166 | static u32 *m8xx_pgcrx[2] = { | 162 | static u32 *m8xx_pgcrx[2]; |
167 | &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcra, | ||
168 | &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcrb | ||
169 | }; | ||
170 | 163 | ||
171 | /* | 164 | /* |
172 | * This structure is used to address each window in the PCMCIA controller. | 165 | * This structure is used to address each window in the PCMCIA controller. |
@@ -228,11 +221,16 @@ struct event_table { | |||
228 | u32 eventbit; | 221 | u32 eventbit; |
229 | }; | 222 | }; |
230 | 223 | ||
224 | static const char driver_name[] = "m8xx-pcmcia"; | ||
225 | |||
231 | struct socket_info { | 226 | struct socket_info { |
232 | void (*handler)(void *info, u32 events); | 227 | void (*handler)(void *info, u32 events); |
233 | void *info; | 228 | void *info; |
234 | 229 | ||
235 | u32 slot; | 230 | u32 slot; |
231 | pcmconf8xx_t *pcmcia; | ||
232 | u32 bus_freq; | ||
233 | int hwirq; | ||
236 | 234 | ||
237 | socket_state_t state; | 235 | socket_state_t state; |
238 | struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO]; | 236 | struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO]; |
@@ -408,78 +406,21 @@ static void hardware_disable(int slot) | |||
408 | #if defined(CONFIG_MPC885ADS) | 406 | #if defined(CONFIG_MPC885ADS) |
409 | 407 | ||
410 | #define PCMCIA_BOARD_MSG "MPC885ADS" | 408 | #define PCMCIA_BOARD_MSG "MPC885ADS" |
409 | #define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V | ||
411 | 410 | ||
412 | static int voltage_set(int slot, int vcc, int vpp) | 411 | static inline void hardware_enable(int slot) |
413 | { | 412 | { |
414 | u32 reg = 0; | 413 | m8xx_pcmcia_ops.hw_ctrl(slot, 1); |
415 | unsigned *bcsr_io; | ||
416 | |||
417 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
418 | |||
419 | switch(vcc) { | ||
420 | case 0: | ||
421 | break; | ||
422 | case 33: | ||
423 | reg |= BCSR1_PCCVCC0; | ||
424 | break; | ||
425 | case 50: | ||
426 | reg |= BCSR1_PCCVCC1; | ||
427 | break; | ||
428 | default: | ||
429 | goto out_unmap; | ||
430 | } | ||
431 | |||
432 | switch(vpp) { | ||
433 | case 0: | ||
434 | break; | ||
435 | case 33: | ||
436 | case 50: | ||
437 | if(vcc == vpp) | ||
438 | reg |= BCSR1_PCCVPP1; | ||
439 | else | ||
440 | goto out_unmap; | ||
441 | break; | ||
442 | case 120: | ||
443 | if ((vcc == 33) || (vcc == 50)) | ||
444 | reg |= BCSR1_PCCVPP0; | ||
445 | else | ||
446 | goto out_unmap; | ||
447 | default: | ||
448 | goto out_unmap; | ||
449 | } | ||
450 | |||
451 | /* first, turn off all power */ | ||
452 | out_be32(bcsr_io, in_be32(bcsr_io) & ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK)); | ||
453 | |||
454 | /* enable new powersettings */ | ||
455 | out_be32(bcsr_io, in_be32(bcsr_io) | reg); | ||
456 | |||
457 | iounmap(bcsr_io); | ||
458 | return 0; | ||
459 | |||
460 | out_unmap: | ||
461 | iounmap(bcsr_io); | ||
462 | return 1; | ||
463 | } | 414 | } |
464 | 415 | ||
465 | #define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V | 416 | static inline void hardware_disable(int slot) |
466 | |||
467 | static void hardware_enable(int slot) | ||
468 | { | 417 | { |
469 | unsigned *bcsr_io; | 418 | m8xx_pcmcia_ops.hw_ctrl(slot, 0); |
470 | |||
471 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
472 | out_be32(bcsr_io, in_be32(bcsr_io) & ~BCSR1_PCCEN); | ||
473 | iounmap(bcsr_io); | ||
474 | } | 419 | } |
475 | 420 | ||
476 | static void hardware_disable(int slot) | 421 | static inline int voltage_set(int slot, int vcc, int vpp) |
477 | { | 422 | { |
478 | unsigned *bcsr_io; | 423 | return m8xx_pcmcia_ops.voltage_set(slot, vcc, vpp); |
479 | |||
480 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
481 | out_be32(bcsr_io, in_be32(bcsr_io) | BCSR1_PCCEN); | ||
482 | iounmap(bcsr_io); | ||
483 | } | 424 | } |
484 | 425 | ||
485 | #endif | 426 | #endif |
@@ -604,48 +545,6 @@ static int voltage_set(int slot, int vcc, int vpp) | |||
604 | 545 | ||
605 | #endif /* CONFIG_PRxK */ | 546 | #endif /* CONFIG_PRxK */ |
606 | 547 | ||
607 | static void m8xx_shutdown(void) | ||
608 | { | ||
609 | u32 m, i; | ||
610 | struct pcmcia_win *w; | ||
611 | |||
612 | for(i = 0; i < PCMCIA_SOCKETS_NO; i++){ | ||
613 | w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; | ||
614 | |||
615 | out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, M8XX_PCMCIA_MASK(i)); | ||
616 | out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & ~M8XX_PCMCIA_MASK(i)); | ||
617 | |||
618 | /* turn off interrupt and disable CxOE */ | ||
619 | out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE); | ||
620 | |||
621 | /* turn off memory windows */ | ||
622 | for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) { | ||
623 | out_be32(&w->or, 0); /* set to not valid */ | ||
624 | w++; | ||
625 | } | ||
626 | |||
627 | /* turn off voltage */ | ||
628 | voltage_set(i, 0, 0); | ||
629 | |||
630 | /* disable external hardware */ | ||
631 | hardware_disable(i); | ||
632 | } | ||
633 | |||
634 | free_irq(pcmcia_schlvl, NULL); | ||
635 | } | ||
636 | |||
637 | static struct device_driver m8xx_driver = { | ||
638 | .name = "m8xx-pcmcia", | ||
639 | .bus = &platform_bus_type, | ||
640 | .suspend = pcmcia_socket_dev_suspend, | ||
641 | .resume = pcmcia_socket_dev_resume, | ||
642 | }; | ||
643 | |||
644 | static struct platform_device m8xx_device = { | ||
645 | .name = "m8xx-pcmcia", | ||
646 | .id = 0, | ||
647 | }; | ||
648 | |||
649 | static u32 pending_events[PCMCIA_SOCKETS_NO]; | 548 | static u32 pending_events[PCMCIA_SOCKETS_NO]; |
650 | static DEFINE_SPINLOCK(pending_event_lock); | 549 | static DEFINE_SPINLOCK(pending_event_lock); |
651 | 550 | ||
@@ -654,13 +553,14 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev) | |||
654 | struct socket_info *s; | 553 | struct socket_info *s; |
655 | struct event_table *e; | 554 | struct event_table *e; |
656 | unsigned int i, events, pscr, pipr, per; | 555 | unsigned int i, events, pscr, pipr, per; |
556 | pcmconf8xx_t *pcmcia = socket[0].pcmcia; | ||
657 | 557 | ||
658 | dprintk("Interrupt!\n"); | 558 | dprintk("Interrupt!\n"); |
659 | /* get interrupt sources */ | 559 | /* get interrupt sources */ |
660 | 560 | ||
661 | pscr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr); | 561 | pscr = in_be32(&pcmcia->pcmc_pscr); |
662 | pipr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr); | 562 | pipr = in_be32(&pcmcia->pcmc_pipr); |
663 | per = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per); | 563 | per = in_be32(&pcmcia->pcmc_per); |
664 | 564 | ||
665 | for(i = 0; i < PCMCIA_SOCKETS_NO; i++) { | 565 | for(i = 0; i < PCMCIA_SOCKETS_NO; i++) { |
666 | s = &socket[i]; | 566 | s = &socket[i]; |
@@ -724,7 +624,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev) | |||
724 | per &= ~M8XX_PCMCIA_RDY_L(0); | 624 | per &= ~M8XX_PCMCIA_RDY_L(0); |
725 | per &= ~M8XX_PCMCIA_RDY_L(1); | 625 | per &= ~M8XX_PCMCIA_RDY_L(1); |
726 | 626 | ||
727 | out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, per); | 627 | out_be32(&pcmcia->pcmc_per, per); |
728 | 628 | ||
729 | if (events) | 629 | if (events) |
730 | pcmcia_parse_events(&socket[i].socket, events); | 630 | pcmcia_parse_events(&socket[i].socket, events); |
@@ -732,7 +632,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev) | |||
732 | } | 632 | } |
733 | 633 | ||
734 | /* clear the interrupt sources */ | 634 | /* clear the interrupt sources */ |
735 | out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, pscr); | 635 | out_be32(&pcmcia->pcmc_pscr, pscr); |
736 | 636 | ||
737 | dprintk("Interrupt done.\n"); | 637 | dprintk("Interrupt done.\n"); |
738 | 638 | ||
@@ -753,7 +653,7 @@ static u32 m8xx_get_graycode(u32 size) | |||
753 | return k; | 653 | return k; |
754 | } | 654 | } |
755 | 655 | ||
756 | static u32 m8xx_get_speed(u32 ns, u32 is_io) | 656 | static u32 m8xx_get_speed(u32 ns, u32 is_io, u32 bus_freq) |
757 | { | 657 | { |
758 | u32 reg, clocks, psst, psl, psht; | 658 | u32 reg, clocks, psst, psl, psht; |
759 | 659 | ||
@@ -781,7 +681,7 @@ static u32 m8xx_get_speed(u32 ns, u32 is_io) | |||
781 | 681 | ||
782 | #define ADJ 180 /* 80 % longer accesstime - to be sure */ | 682 | #define ADJ 180 /* 80 % longer accesstime - to be sure */ |
783 | 683 | ||
784 | clocks = ((M8XX_BUSFREQ / 1000) * ns) / 1000; | 684 | clocks = ((bus_freq / 1000) * ns) / 1000; |
785 | clocks = (clocks * ADJ) / (100*1000); | 685 | clocks = (clocks * ADJ) / (100*1000); |
786 | if(clocks >= PCMCIA_BMT_LIMIT) { | 686 | if(clocks >= PCMCIA_BMT_LIMIT) { |
787 | printk( "Max access time limit reached\n"); | 687 | printk( "Max access time limit reached\n"); |
@@ -806,8 +706,9 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value) | |||
806 | int lsock = container_of(sock, struct socket_info, socket)->slot; | 706 | int lsock = container_of(sock, struct socket_info, socket)->slot; |
807 | struct socket_info *s = &socket[lsock]; | 707 | struct socket_info *s = &socket[lsock]; |
808 | unsigned int pipr, reg; | 708 | unsigned int pipr, reg; |
709 | pcmconf8xx_t *pcmcia = s->pcmcia; | ||
809 | 710 | ||
810 | pipr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr); | 711 | pipr = in_be32(&pcmcia->pcmc_pipr); |
811 | 712 | ||
812 | *value = ((pipr & (M8XX_PCMCIA_CD1(lsock) | 713 | *value = ((pipr & (M8XX_PCMCIA_CD1(lsock) |
813 | | M8XX_PCMCIA_CD2(lsock))) == 0) ? SS_DETECT : 0; | 714 | | M8XX_PCMCIA_CD2(lsock))) == 0) ? SS_DETECT : 0; |
@@ -918,6 +819,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | |||
918 | struct event_table *e; | 819 | struct event_table *e; |
919 | unsigned int reg; | 820 | unsigned int reg; |
920 | unsigned long flags; | 821 | unsigned long flags; |
822 | pcmconf8xx_t *pcmcia = socket[0].pcmcia; | ||
921 | 823 | ||
922 | dprintk( "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " | 824 | dprintk( "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " |
923 | "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags, | 825 | "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags, |
@@ -927,6 +829,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | |||
927 | if(voltage_set(lsock, state->Vcc, state->Vpp)) | 829 | if(voltage_set(lsock, state->Vcc, state->Vpp)) |
928 | return -EINVAL; | 830 | return -EINVAL; |
929 | 831 | ||
832 | |||
930 | /* Take care of reset... */ | 833 | /* Take care of reset... */ |
931 | if(state->flags & SS_RESET) | 834 | if(state->flags & SS_RESET) |
932 | out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXRESET); /* active high */ | 835 | out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXRESET); /* active high */ |
@@ -982,7 +885,8 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | |||
982 | * If io_irq is non-zero we should enable irq. | 885 | * If io_irq is non-zero we should enable irq. |
983 | */ | 886 | */ |
984 | if(state->io_irq) { | 887 | if(state->io_irq) { |
985 | out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | mk_int_int_mask(state->io_irq) << 24); | 888 | out_be32(M8XX_PGCRX(lsock), |
889 | in_be32(M8XX_PGCRX(lsock)) | mk_int_int_mask(s->hwirq) << 24); | ||
986 | /* | 890 | /* |
987 | * Strange thing here: | 891 | * Strange thing here: |
988 | * The manual does not tell us which interrupt | 892 | * The manual does not tell us which interrupt |
@@ -1027,7 +931,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | |||
1027 | * Writing ones will clear the bits. | 931 | * Writing ones will clear the bits. |
1028 | */ | 932 | */ |
1029 | 933 | ||
1030 | out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, reg); | 934 | out_be32(&pcmcia->pcmc_pscr, reg); |
1031 | 935 | ||
1032 | /* | 936 | /* |
1033 | * Write the mask. | 937 | * Write the mask. |
@@ -1036,15 +940,8 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | |||
1036 | * Ones will enable the interrupt. | 940 | * Ones will enable the interrupt. |
1037 | */ | 941 | */ |
1038 | 942 | ||
1039 | /* | 943 | reg |= in_be32(&pcmcia->pcmc_per) & (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1)); |
1040 | reg |= ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per | 944 | out_be32(&pcmcia->pcmc_per, reg); |
1041 | & M8XX_PCMCIA_MASK(lsock); | ||
1042 | */ | ||
1043 | |||
1044 | reg |= in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & | ||
1045 | (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1)); | ||
1046 | |||
1047 | out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, reg); | ||
1048 | 945 | ||
1049 | spin_unlock_irqrestore(&events_lock, flags); | 946 | spin_unlock_irqrestore(&events_lock, flags); |
1050 | 947 | ||
@@ -1062,6 +959,8 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) | |||
1062 | struct socket_info *s = &socket[lsock]; | 959 | struct socket_info *s = &socket[lsock]; |
1063 | struct pcmcia_win *w; | 960 | struct pcmcia_win *w; |
1064 | unsigned int reg, winnr; | 961 | unsigned int reg, winnr; |
962 | pcmconf8xx_t *pcmcia = s->pcmcia; | ||
963 | |||
1065 | 964 | ||
1066 | #define M8XX_SIZE (io->stop - io->start + 1) | 965 | #define M8XX_SIZE (io->stop - io->start + 1) |
1067 | #define M8XX_BASE (PCMCIA_IO_WIN_BASE + io->start) | 966 | #define M8XX_BASE (PCMCIA_IO_WIN_BASE + io->start) |
@@ -1086,7 +985,7 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) | |||
1086 | 985 | ||
1087 | /* setup registers */ | 986 | /* setup registers */ |
1088 | 987 | ||
1089 | w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; | 988 | w = (void *) &pcmcia->pcmc_pbr0; |
1090 | w += winnr; | 989 | w += winnr; |
1091 | 990 | ||
1092 | out_be32(&w->or, 0); /* turn off window first */ | 991 | out_be32(&w->or, 0); /* turn off window first */ |
@@ -1095,12 +994,13 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) | |||
1095 | reg <<= 27; | 994 | reg <<= 27; |
1096 | reg |= M8XX_PCMCIA_POR_IO |(lsock << 2); | 995 | reg |= M8XX_PCMCIA_POR_IO |(lsock << 2); |
1097 | 996 | ||
1098 | reg |= m8xx_get_speed(io->speed, 1); | 997 | reg |= m8xx_get_speed(io->speed, 1, s->bus_freq); |
1099 | 998 | ||
1100 | if(io->flags & MAP_WRPROT) | 999 | if(io->flags & MAP_WRPROT) |
1101 | reg |= M8XX_PCMCIA_POR_WRPROT; | 1000 | reg |= M8XX_PCMCIA_POR_WRPROT; |
1102 | 1001 | ||
1103 | if(io->flags & (MAP_16BIT | MAP_AUTOSZ)) | 1002 | /*if(io->flags & (MAP_16BIT | MAP_AUTOSZ))*/ |
1003 | if(io->flags & MAP_16BIT) | ||
1104 | reg |= M8XX_PCMCIA_POR_16BIT; | 1004 | reg |= M8XX_PCMCIA_POR_16BIT; |
1105 | 1005 | ||
1106 | if(io->flags & MAP_ACTIVE) | 1006 | if(io->flags & MAP_ACTIVE) |
@@ -1117,7 +1017,7 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) | |||
1117 | 1017 | ||
1118 | /* setup registers */ | 1018 | /* setup registers */ |
1119 | 1019 | ||
1120 | w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; | 1020 | w = (void *) &pcmcia->pcmc_pbr0; |
1121 | w += winnr; | 1021 | w += winnr; |
1122 | 1022 | ||
1123 | out_be32(&w->or, 0); /* turn off window */ | 1023 | out_be32(&w->or, 0); /* turn off window */ |
@@ -1144,6 +1044,7 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m | |||
1144 | struct pcmcia_win *w; | 1044 | struct pcmcia_win *w; |
1145 | struct pccard_mem_map *old; | 1045 | struct pccard_mem_map *old; |
1146 | unsigned int reg, winnr; | 1046 | unsigned int reg, winnr; |
1047 | pcmconf8xx_t *pcmcia = s->pcmcia; | ||
1147 | 1048 | ||
1148 | dprintk( "SetMemMap(%d, %d, %#2.2x, %d ns, " | 1049 | dprintk( "SetMemMap(%d, %d, %#2.2x, %d ns, " |
1149 | "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags, | 1050 | "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags, |
@@ -1166,12 +1067,12 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m | |||
1166 | 1067 | ||
1167 | /* Setup the window in the pcmcia controller */ | 1068 | /* Setup the window in the pcmcia controller */ |
1168 | 1069 | ||
1169 | w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; | 1070 | w = (void *) &pcmcia->pcmc_pbr0; |
1170 | w += winnr; | 1071 | w += winnr; |
1171 | 1072 | ||
1172 | reg |= lsock << 2; | 1073 | reg |= lsock << 2; |
1173 | 1074 | ||
1174 | reg |= m8xx_get_speed(mem->speed, 0); | 1075 | reg |= m8xx_get_speed(mem->speed, 0, s->bus_freq); |
1175 | 1076 | ||
1176 | if(mem->flags & MAP_ATTRIB) | 1077 | if(mem->flags & MAP_ATTRIB) |
1177 | reg |= M8XX_PCMCIA_POR_ATTRMEM; | 1078 | reg |= M8XX_PCMCIA_POR_ATTRMEM; |
@@ -1236,60 +1137,69 @@ static int m8xx_sock_init(struct pcmcia_socket *sock) | |||
1236 | 1137 | ||
1237 | } | 1138 | } |
1238 | 1139 | ||
1239 | static int m8xx_suspend(struct pcmcia_socket *sock) | 1140 | static int m8xx_sock_suspend(struct pcmcia_socket *sock) |
1240 | { | 1141 | { |
1241 | return m8xx_set_socket(sock, &dead_socket); | 1142 | return m8xx_set_socket(sock, &dead_socket); |
1242 | } | 1143 | } |
1243 | 1144 | ||
1244 | static struct pccard_operations m8xx_services = { | 1145 | static struct pccard_operations m8xx_services = { |
1245 | .init = m8xx_sock_init, | 1146 | .init = m8xx_sock_init, |
1246 | .suspend = m8xx_suspend, | 1147 | .suspend = m8xx_sock_suspend, |
1247 | .get_status = m8xx_get_status, | 1148 | .get_status = m8xx_get_status, |
1248 | .set_socket = m8xx_set_socket, | 1149 | .set_socket = m8xx_set_socket, |
1249 | .set_io_map = m8xx_set_io_map, | 1150 | .set_io_map = m8xx_set_io_map, |
1250 | .set_mem_map = m8xx_set_mem_map, | 1151 | .set_mem_map = m8xx_set_mem_map, |
1251 | }; | 1152 | }; |
1252 | 1153 | ||
1253 | static int __init m8xx_init(void) | 1154 | static int __init m8xx_probe(struct of_device *ofdev, const struct of_device_id *match) |
1254 | { | 1155 | { |
1255 | struct pcmcia_win *w; | 1156 | struct pcmcia_win *w; |
1256 | unsigned int i,m; | 1157 | unsigned int i, m, hwirq; |
1158 | pcmconf8xx_t *pcmcia; | ||
1159 | int status; | ||
1160 | struct device_node *np = ofdev->node; | ||
1257 | 1161 | ||
1258 | pcmcia_info("%s\n", version); | 1162 | pcmcia_info("%s\n", version); |
1259 | 1163 | ||
1260 | if (driver_register(&m8xx_driver)) | 1164 | pcmcia = of_iomap(np, 0); |
1261 | return -1; | 1165 | if(pcmcia == NULL) |
1166 | return -EINVAL; | ||
1167 | |||
1168 | pcmcia_schlvl = irq_of_parse_and_map(np, 0); | ||
1169 | hwirq = irq_map[pcmcia_schlvl].hwirq; | ||
1170 | if (pcmcia_schlvl < 0) | ||
1171 | return -EINVAL; | ||
1172 | |||
1173 | m8xx_pgcrx[0] = &pcmcia->pcmc_pgcra; | ||
1174 | m8xx_pgcrx[1] = &pcmcia->pcmc_pgcrb; | ||
1175 | |||
1262 | 1176 | ||
1263 | pcmcia_info(PCMCIA_BOARD_MSG " using " PCMCIA_SLOT_MSG | 1177 | pcmcia_info(PCMCIA_BOARD_MSG " using " PCMCIA_SLOT_MSG |
1264 | " with IRQ %u.\n", pcmcia_schlvl); | 1178 | " with IRQ %u (%d). \n", pcmcia_schlvl, hwirq); |
1265 | 1179 | ||
1266 | /* Configure Status change interrupt */ | 1180 | /* Configure Status change interrupt */ |
1267 | 1181 | ||
1268 | if(request_irq(pcmcia_schlvl, m8xx_interrupt, 0, | 1182 | if(request_irq(pcmcia_schlvl, m8xx_interrupt, IRQF_SHARED, |
1269 | "m8xx_pcmcia", NULL)) { | 1183 | driver_name, socket)) { |
1270 | pcmcia_error("Cannot allocate IRQ %u for SCHLVL!\n", | 1184 | pcmcia_error("Cannot allocate IRQ %u for SCHLVL!\n", |
1271 | pcmcia_schlvl); | 1185 | pcmcia_schlvl); |
1272 | return -1; | 1186 | return -1; |
1273 | } | 1187 | } |
1274 | 1188 | ||
1275 | w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; | 1189 | w = (void *) &pcmcia->pcmc_pbr0; |
1276 | |||
1277 | out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, | ||
1278 | M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1)); | ||
1279 | 1190 | ||
1280 | out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, | 1191 | out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1)); |
1281 | in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & | 1192 | clrbits32(&pcmcia->pcmc_per, M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1)); |
1282 | ~(M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1))); | ||
1283 | 1193 | ||
1284 | /* connect interrupt and disable CxOE */ | 1194 | /* connect interrupt and disable CxOE */ |
1285 | 1195 | ||
1286 | out_be32(M8XX_PGCRX(0), M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16)); | 1196 | out_be32(M8XX_PGCRX(0), M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16)); |
1287 | out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16)); | 1197 | out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16)); |
1288 | 1198 | ||
1289 | /* intialize the fixed memory windows */ | 1199 | /* intialize the fixed memory windows */ |
1290 | 1200 | ||
1291 | for(i = 0; i < PCMCIA_SOCKETS_NO; i++){ | 1201 | for(i = 0; i < PCMCIA_SOCKETS_NO; i++){ |
1292 | for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) { | 1202 | for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) { |
1293 | out_be32(&w->br, PCMCIA_MEM_WIN_BASE + | 1203 | out_be32(&w->br, PCMCIA_MEM_WIN_BASE + |
1294 | (PCMCIA_MEM_WIN_SIZE | 1204 | (PCMCIA_MEM_WIN_SIZE |
1295 | * (m + i * PCMCIA_MEM_WIN_NO))); | 1205 | * (m + i * PCMCIA_MEM_WIN_NO))); |
@@ -1300,16 +1210,14 @@ static int __init m8xx_init(void) | |||
1300 | } | 1210 | } |
1301 | } | 1211 | } |
1302 | 1212 | ||
1303 | /* turn off voltage */ | 1213 | /* turn off voltage */ |
1304 | voltage_set(0, 0, 0); | 1214 | voltage_set(0, 0, 0); |
1305 | voltage_set(1, 0, 0); | 1215 | voltage_set(1, 0, 0); |
1306 | 1216 | ||
1307 | /* Enable external hardware */ | 1217 | /* Enable external hardware */ |
1308 | hardware_enable(0); | 1218 | hardware_enable(0); |
1309 | hardware_enable(1); | 1219 | hardware_enable(1); |
1310 | 1220 | ||
1311 | platform_device_register(&m8xx_device); | ||
1312 | |||
1313 | for (i = 0 ; i < PCMCIA_SOCKETS_NO; i++) { | 1221 | for (i = 0 ; i < PCMCIA_SOCKETS_NO; i++) { |
1314 | socket[i].slot = i; | 1222 | socket[i].slot = i; |
1315 | socket[i].socket.owner = THIS_MODULE; | 1223 | socket[i].socket.owner = THIS_MODULE; |
@@ -1317,30 +1225,105 @@ static int __init m8xx_init(void) | |||
1317 | socket[i].socket.irq_mask = 0x000; | 1225 | socket[i].socket.irq_mask = 0x000; |
1318 | socket[i].socket.map_size = 0x1000; | 1226 | socket[i].socket.map_size = 0x1000; |
1319 | socket[i].socket.io_offset = 0; | 1227 | socket[i].socket.io_offset = 0; |
1320 | socket[i].socket.pci_irq = i ? 7 : 9; | 1228 | socket[i].socket.pci_irq = pcmcia_schlvl; |
1321 | socket[i].socket.ops = &m8xx_services; | 1229 | socket[i].socket.ops = &m8xx_services; |
1322 | socket[i].socket.resource_ops = &pccard_iodyn_ops; | 1230 | socket[i].socket.resource_ops = &pccard_nonstatic_ops; |
1323 | socket[i].socket.cb_dev = NULL; | 1231 | socket[i].socket.cb_dev = NULL; |
1324 | socket[i].socket.dev.parent = &m8xx_device.dev; | 1232 | socket[i].socket.dev.parent = &ofdev->dev; |
1233 | socket[i].pcmcia = pcmcia; | ||
1234 | socket[i].bus_freq = ppc_proc_freq; | ||
1235 | socket[i].hwirq = hwirq; | ||
1236 | |||
1237 | |||
1325 | } | 1238 | } |
1326 | 1239 | ||
1327 | for (i = 0; i < PCMCIA_SOCKETS_NO; i++) | 1240 | for (i = 0; i < PCMCIA_SOCKETS_NO; i++) { |
1328 | pcmcia_register_socket(&socket[i].socket); | 1241 | status = pcmcia_register_socket(&socket[i].socket); |
1242 | if (status < 0) | ||
1243 | pcmcia_error("Socket register failed\n"); | ||
1244 | } | ||
1329 | 1245 | ||
1330 | return 0; | 1246 | return 0; |
1331 | } | 1247 | } |
1332 | 1248 | ||
1333 | static void __exit m8xx_exit(void) | 1249 | static int m8xx_remove(struct of_device* ofdev) |
1334 | { | 1250 | { |
1335 | int i; | 1251 | u32 m, i; |
1252 | struct pcmcia_win *w; | ||
1253 | pcmconf8xx_t *pcmcia = socket[0].pcmcia; | ||
1254 | |||
1255 | for (i = 0; i < PCMCIA_SOCKETS_NO; i++) { | ||
1256 | w = (void *) &pcmcia->pcmc_pbr0; | ||
1257 | |||
1258 | out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(i)); | ||
1259 | out_be32(&pcmcia->pcmc_per, | ||
1260 | in_be32(&pcmcia->pcmc_per) & ~M8XX_PCMCIA_MASK(i)); | ||
1336 | 1261 | ||
1262 | /* turn off interrupt and disable CxOE */ | ||
1263 | out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE); | ||
1264 | |||
1265 | /* turn off memory windows */ | ||
1266 | for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) { | ||
1267 | out_be32(&w->or, 0); /* set to not valid */ | ||
1268 | w++; | ||
1269 | } | ||
1270 | |||
1271 | /* turn off voltage */ | ||
1272 | voltage_set(i, 0, 0); | ||
1273 | |||
1274 | /* disable external hardware */ | ||
1275 | hardware_disable(i); | ||
1276 | } | ||
1337 | for (i = 0; i < PCMCIA_SOCKETS_NO; i++) | 1277 | for (i = 0; i < PCMCIA_SOCKETS_NO; i++) |
1338 | pcmcia_unregister_socket(&socket[i].socket); | 1278 | pcmcia_unregister_socket(&socket[i].socket); |
1339 | 1279 | ||
1340 | m8xx_shutdown(); | 1280 | free_irq(pcmcia_schlvl, NULL); |
1341 | 1281 | ||
1342 | platform_device_unregister(&m8xx_device); | 1282 | return 0; |
1343 | driver_unregister(&m8xx_driver); | 1283 | } |
1284 | |||
1285 | #ifdef CONFIG_PM | ||
1286 | static int m8xx_suspend(struct platform_device *pdev, pm_message_t state) | ||
1287 | { | ||
1288 | return pcmcia_socket_dev_suspend(&pdev->dev, state); | ||
1289 | } | ||
1290 | |||
1291 | static int m8xx_resume(struct platform_device *pdev) | ||
1292 | { | ||
1293 | return pcmcia_socket_dev_resume(&pdev->dev); | ||
1294 | } | ||
1295 | #else | ||
1296 | #define m8xx_suspend NULL | ||
1297 | #define m8xx_resume NULL | ||
1298 | #endif | ||
1299 | |||
1300 | static struct of_device_id m8xx_pcmcia_match[] = { | ||
1301 | { | ||
1302 | .type = "pcmcia", | ||
1303 | .compatible = "fsl,pq-pcmcia", | ||
1304 | }, | ||
1305 | {}, | ||
1306 | }; | ||
1307 | |||
1308 | MODULE_DEVICE_TABLE(of, m8xx_pcmcia_match); | ||
1309 | |||
1310 | static struct of_platform_driver m8xx_pcmcia_driver = { | ||
1311 | .name = (char *) driver_name, | ||
1312 | .match_table = m8xx_pcmcia_match, | ||
1313 | .probe = m8xx_probe, | ||
1314 | .remove = m8xx_remove, | ||
1315 | .suspend = m8xx_suspend, | ||
1316 | .resume = m8xx_resume, | ||
1317 | }; | ||
1318 | |||
1319 | static int __init m8xx_init(void) | ||
1320 | { | ||
1321 | return of_register_platform_driver(&m8xx_pcmcia_driver); | ||
1322 | } | ||
1323 | |||
1324 | static void __exit m8xx_exit(void) | ||
1325 | { | ||
1326 | of_unregister_platform_driver(&m8xx_pcmcia_driver); | ||
1344 | } | 1327 | } |
1345 | 1328 | ||
1346 | module_init(m8xx_init); | 1329 | module_init(m8xx_init); |
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile index e251d1c1171c..746031de2195 100644 --- a/drivers/ps3/Makefile +++ b/drivers/ps3/Makefile | |||
@@ -1,3 +1,6 @@ | |||
1 | obj-$(CONFIG_PS3_VUART) += vuart.o | 1 | obj-$(CONFIG_PS3_VUART) += vuart.o |
2 | obj-$(CONFIG_PS3_PS3AV) += ps3av.o ps3av_cmd.o | 2 | obj-$(CONFIG_PS3_PS3AV) += ps3av_mod.o |
3 | ps3av_mod-objs += ps3av.o ps3av_cmd.o | ||
4 | obj-$(CONFIG_PPC_PS3) += sys-manager-core.o | ||
3 | obj-$(CONFIG_PS3_SYS_MANAGER) += sys-manager.o | 5 | obj-$(CONFIG_PS3_SYS_MANAGER) += sys-manager.o |
6 | obj-$(CONFIG_PS3_STORAGE) += ps3stor_lib.o | ||
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c index 1393e64335f9..85e21614f868 100644 --- a/drivers/ps3/ps3av.c +++ b/drivers/ps3/ps3av.c | |||
@@ -1,32 +1,30 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2006 Sony Computer Entertainment Inc. | 2 | * PS3 AV backend support. |
3 | * Copyright 2006, 2007 Sony Corporation | ||
4 | * | 3 | * |
5 | * AV backend support for PS3 | 4 | * Copyright (C) 2007 Sony Computer Entertainment Inc. |
5 | * Copyright 2007 Sony Corp. | ||
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * under the terms of the GNU General Public License as published | 8 | * it under the terms of the GNU General Public License as published by |
9 | * by the Free Software Foundation; version 2 of the License. | 9 | * the Free Software Foundation; version 2 of the License. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, but | 11 | * This program is distributed in the hope that it will be useful, |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public License along | 16 | * You should have received a copy of the GNU General Public License |
17 | * with this program; if not, write to the Free Software Foundation, Inc., | 17 | * along with this program; if not, write to the Free Software |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | 22 | #include <linux/module.h> |
22 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
23 | #include <linux/notifier.h> | 24 | #include <linux/notifier.h> |
24 | #include <linux/reboot.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/ioctl.h> | 25 | #include <linux/ioctl.h> |
27 | 26 | ||
28 | #include <asm/firmware.h> | 27 | #include <asm/firmware.h> |
29 | #include <asm/lv1call.h> | ||
30 | #include <asm/ps3av.h> | 28 | #include <asm/ps3av.h> |
31 | #include <asm/ps3.h> | 29 | #include <asm/ps3.h> |
32 | 30 | ||
@@ -39,13 +37,12 @@ static int timeout = 5000; /* in msec ( 5 sec ) */ | |||
39 | module_param(timeout, int, 0644); | 37 | module_param(timeout, int, 0644); |
40 | 38 | ||
41 | static struct ps3av { | 39 | static struct ps3av { |
42 | int available; | ||
43 | struct mutex mutex; | 40 | struct mutex mutex; |
44 | struct work_struct work; | 41 | struct work_struct work; |
45 | struct completion done; | 42 | struct completion done; |
46 | struct workqueue_struct *wq; | 43 | struct workqueue_struct *wq; |
47 | int open_count; | 44 | int open_count; |
48 | struct ps3_vuart_port_device *dev; | 45 | struct ps3_system_bus_device *dev; |
49 | 46 | ||
50 | int region; | 47 | int region; |
51 | struct ps3av_pkt_av_get_hw_conf av_hw_conf; | 48 | struct ps3av_pkt_av_get_hw_conf av_hw_conf; |
@@ -55,11 +52,13 @@ static struct ps3av { | |||
55 | u32 audio_port; | 52 | u32 audio_port; |
56 | int ps3av_mode; | 53 | int ps3av_mode; |
57 | int ps3av_mode_old; | 54 | int ps3av_mode_old; |
58 | } ps3av; | 55 | union { |
59 | 56 | struct ps3av_reply_hdr reply_hdr; | |
60 | static struct ps3_vuart_port_device ps3av_dev = { | 57 | u8 raw[PS3AV_BUF_SIZE]; |
61 | .match_id = PS3_MATCH_ID_AV_SETTINGS | 58 | } recv_buf; |
62 | }; | 59 | void (*flip_ctl)(int on, void *data); |
60 | void *flip_data; | ||
61 | } *ps3av; | ||
63 | 62 | ||
64 | /* color space */ | 63 | /* color space */ |
65 | #define YUV444 PS3AV_CMD_VIDEO_CS_YUV444_8 | 64 | #define YUV444 PS3AV_CMD_VIDEO_CS_YUV444_8 |
@@ -169,7 +168,7 @@ static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr) | |||
169 | if (hdr->cid & PS3AV_EVENT_CMD_MASK) { | 168 | if (hdr->cid & PS3AV_EVENT_CMD_MASK) { |
170 | table = ps3av_search_cmd_table(hdr->cid, PS3AV_EVENT_CMD_MASK); | 169 | table = ps3av_search_cmd_table(hdr->cid, PS3AV_EVENT_CMD_MASK); |
171 | if (table) | 170 | if (table) |
172 | dev_dbg(&ps3av_dev.core, | 171 | dev_dbg(&ps3av->dev->core, |
173 | "recv event packet cid:%08x port:0x%x size:%d\n", | 172 | "recv event packet cid:%08x port:0x%x size:%d\n", |
174 | hdr->cid, ps3av_event_get_port_id(hdr->cid), | 173 | hdr->cid, ps3av_event_get_port_id(hdr->cid), |
175 | hdr->size); | 174 | hdr->size); |
@@ -182,6 +181,41 @@ static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr) | |||
182 | return 0; | 181 | return 0; |
183 | } | 182 | } |
184 | 183 | ||
184 | |||
185 | #define POLLING_INTERVAL 25 /* in msec */ | ||
186 | |||
187 | static int ps3av_vuart_write(struct ps3_system_bus_device *dev, | ||
188 | const void *buf, unsigned long size) | ||
189 | { | ||
190 | int error; | ||
191 | dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); | ||
192 | error = ps3_vuart_write(dev, buf, size); | ||
193 | dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); | ||
194 | return error ? error : size; | ||
195 | } | ||
196 | |||
197 | static int ps3av_vuart_read(struct ps3_system_bus_device *dev, void *buf, | ||
198 | unsigned long size, int timeout) | ||
199 | { | ||
200 | int error; | ||
201 | int loopcnt = 0; | ||
202 | |||
203 | dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); | ||
204 | timeout = (timeout + POLLING_INTERVAL - 1) / POLLING_INTERVAL; | ||
205 | while (loopcnt++ <= timeout) { | ||
206 | error = ps3_vuart_read(dev, buf, size); | ||
207 | if (!error) | ||
208 | return size; | ||
209 | if (error != -EAGAIN) { | ||
210 | printk(KERN_ERR "%s: ps3_vuart_read failed %d\n", | ||
211 | __func__, error); | ||
212 | return error; | ||
213 | } | ||
214 | msleep(POLLING_INTERVAL); | ||
215 | } | ||
216 | return -EWOULDBLOCK; | ||
217 | } | ||
218 | |||
185 | static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, | 219 | static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, |
186 | struct ps3av_reply_hdr *recv_buf, int write_len, | 220 | struct ps3av_reply_hdr *recv_buf, int write_len, |
187 | int read_len) | 221 | int read_len) |
@@ -190,13 +224,13 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, | |||
190 | u32 cmd; | 224 | u32 cmd; |
191 | int event; | 225 | int event; |
192 | 226 | ||
193 | if (!ps3av.available) | 227 | if (!ps3av) |
194 | return -ENODEV; | 228 | return -ENODEV; |
195 | 229 | ||
196 | /* send pkt */ | 230 | /* send pkt */ |
197 | res = ps3av_vuart_write(ps3av.dev, send_buf, write_len); | 231 | res = ps3av_vuart_write(ps3av->dev, send_buf, write_len); |
198 | if (res < 0) { | 232 | if (res < 0) { |
199 | dev_dbg(&ps3av_dev.core, | 233 | dev_dbg(&ps3av->dev->core, |
200 | "%s: ps3av_vuart_write() failed (result=%d)\n", | 234 | "%s: ps3av_vuart_write() failed (result=%d)\n", |
201 | __func__, res); | 235 | __func__, res); |
202 | return res; | 236 | return res; |
@@ -206,20 +240,20 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, | |||
206 | cmd = send_buf->cid; | 240 | cmd = send_buf->cid; |
207 | do { | 241 | do { |
208 | /* read header */ | 242 | /* read header */ |
209 | res = ps3av_vuart_read(ps3av.dev, recv_buf, PS3AV_HDR_SIZE, | 243 | res = ps3av_vuart_read(ps3av->dev, recv_buf, PS3AV_HDR_SIZE, |
210 | timeout); | 244 | timeout); |
211 | if (res != PS3AV_HDR_SIZE) { | 245 | if (res != PS3AV_HDR_SIZE) { |
212 | dev_dbg(&ps3av_dev.core, | 246 | dev_dbg(&ps3av->dev->core, |
213 | "%s: ps3av_vuart_read() failed (result=%d)\n", | 247 | "%s: ps3av_vuart_read() failed (result=%d)\n", |
214 | __func__, res); | 248 | __func__, res); |
215 | return res; | 249 | return res; |
216 | } | 250 | } |
217 | 251 | ||
218 | /* read body */ | 252 | /* read body */ |
219 | res = ps3av_vuart_read(ps3av.dev, &recv_buf->cid, | 253 | res = ps3av_vuart_read(ps3av->dev, &recv_buf->cid, |
220 | recv_buf->size, timeout); | 254 | recv_buf->size, timeout); |
221 | if (res < 0) { | 255 | if (res < 0) { |
222 | dev_dbg(&ps3av_dev.core, | 256 | dev_dbg(&ps3av->dev->core, |
223 | "%s: ps3av_vuart_read() failed (result=%d)\n", | 257 | "%s: ps3av_vuart_read() failed (result=%d)\n", |
224 | __func__, res); | 258 | __func__, res); |
225 | return res; | 259 | return res; |
@@ -230,7 +264,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, | |||
230 | } while (event); | 264 | } while (event); |
231 | 265 | ||
232 | if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) { | 266 | if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) { |
233 | dev_dbg(&ps3av_dev.core, "%s: reply err (result=%x)\n", | 267 | dev_dbg(&ps3av->dev->core, "%s: reply err (result=%x)\n", |
234 | __func__, recv_buf->cid); | 268 | __func__, recv_buf->cid); |
235 | return -EINVAL; | 269 | return -EINVAL; |
236 | } | 270 | } |
@@ -245,7 +279,7 @@ static int ps3av_process_reply_packet(struct ps3av_send_hdr *cmd_buf, | |||
245 | int return_len; | 279 | int return_len; |
246 | 280 | ||
247 | if (recv_buf->version != PS3AV_VERSION) { | 281 | if (recv_buf->version != PS3AV_VERSION) { |
248 | dev_dbg(&ps3av_dev.core, "reply_packet invalid version:%x\n", | 282 | dev_dbg(&ps3av->dev->core, "reply_packet invalid version:%x\n", |
249 | recv_buf->version); | 283 | recv_buf->version); |
250 | return -EFAULT; | 284 | return -EFAULT; |
251 | } | 285 | } |
@@ -267,16 +301,11 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, | |||
267 | struct ps3av_send_hdr *buf) | 301 | struct ps3av_send_hdr *buf) |
268 | { | 302 | { |
269 | int res = 0; | 303 | int res = 0; |
270 | static union { | ||
271 | struct ps3av_reply_hdr reply_hdr; | ||
272 | u8 raw[PS3AV_BUF_SIZE]; | ||
273 | } recv_buf; | ||
274 | |||
275 | u32 *table; | 304 | u32 *table; |
276 | 305 | ||
277 | BUG_ON(!ps3av.available); | 306 | BUG_ON(!ps3av); |
278 | 307 | ||
279 | mutex_lock(&ps3av.mutex); | 308 | mutex_lock(&ps3av->mutex); |
280 | 309 | ||
281 | table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK); | 310 | table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK); |
282 | BUG_ON(!table); | 311 | BUG_ON(!table); |
@@ -288,7 +317,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, | |||
288 | ps3av_set_hdr(cid, send_len, buf); | 317 | ps3av_set_hdr(cid, send_len, buf); |
289 | 318 | ||
290 | /* send packet via vuart */ | 319 | /* send packet via vuart */ |
291 | res = ps3av_send_cmd_pkt(buf, &recv_buf.reply_hdr, send_len, | 320 | res = ps3av_send_cmd_pkt(buf, &ps3av->recv_buf.reply_hdr, send_len, |
292 | usr_buf_size); | 321 | usr_buf_size); |
293 | if (res < 0) { | 322 | if (res < 0) { |
294 | printk(KERN_ERR | 323 | printk(KERN_ERR |
@@ -298,7 +327,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, | |||
298 | } | 327 | } |
299 | 328 | ||
300 | /* process reply packet */ | 329 | /* process reply packet */ |
301 | res = ps3av_process_reply_packet(buf, &recv_buf.reply_hdr, | 330 | res = ps3av_process_reply_packet(buf, &ps3av->recv_buf.reply_hdr, |
302 | usr_buf_size); | 331 | usr_buf_size); |
303 | if (res < 0) { | 332 | if (res < 0) { |
304 | printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n", | 333 | printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n", |
@@ -306,11 +335,11 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, | |||
306 | goto err; | 335 | goto err; |
307 | } | 336 | } |
308 | 337 | ||
309 | mutex_unlock(&ps3av.mutex); | 338 | mutex_unlock(&ps3av->mutex); |
310 | return 0; | 339 | return 0; |
311 | 340 | ||
312 | err: | 341 | err: |
313 | mutex_unlock(&ps3av.mutex); | 342 | mutex_unlock(&ps3av->mutex); |
314 | printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res); | 343 | printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res); |
315 | return res; | 344 | return res; |
316 | } | 345 | } |
@@ -319,11 +348,11 @@ static int ps3av_set_av_video_mute(u32 mute) | |||
319 | { | 348 | { |
320 | int i, num_of_av_port, res; | 349 | int i, num_of_av_port, res; |
321 | 350 | ||
322 | num_of_av_port = ps3av.av_hw_conf.num_of_hdmi + | 351 | num_of_av_port = ps3av->av_hw_conf.num_of_hdmi + |
323 | ps3av.av_hw_conf.num_of_avmulti; | 352 | ps3av->av_hw_conf.num_of_avmulti; |
324 | /* video mute on */ | 353 | /* video mute on */ |
325 | for (i = 0; i < num_of_av_port; i++) { | 354 | for (i = 0; i < num_of_av_port; i++) { |
326 | res = ps3av_cmd_av_video_mute(1, &ps3av.av_port[i], mute); | 355 | res = ps3av_cmd_av_video_mute(1, &ps3av->av_port[i], mute); |
327 | if (res < 0) | 356 | if (res < 0) |
328 | return -1; | 357 | return -1; |
329 | } | 358 | } |
@@ -335,13 +364,13 @@ static int ps3av_set_video_disable_sig(void) | |||
335 | { | 364 | { |
336 | int i, num_of_hdmi_port, num_of_av_port, res; | 365 | int i, num_of_hdmi_port, num_of_av_port, res; |
337 | 366 | ||
338 | num_of_hdmi_port = ps3av.av_hw_conf.num_of_hdmi; | 367 | num_of_hdmi_port = ps3av->av_hw_conf.num_of_hdmi; |
339 | num_of_av_port = ps3av.av_hw_conf.num_of_hdmi + | 368 | num_of_av_port = ps3av->av_hw_conf.num_of_hdmi + |
340 | ps3av.av_hw_conf.num_of_avmulti; | 369 | ps3av->av_hw_conf.num_of_avmulti; |
341 | 370 | ||
342 | /* tv mute */ | 371 | /* tv mute */ |
343 | for (i = 0; i < num_of_hdmi_port; i++) { | 372 | for (i = 0; i < num_of_hdmi_port; i++) { |
344 | res = ps3av_cmd_av_tv_mute(ps3av.av_port[i], | 373 | res = ps3av_cmd_av_tv_mute(ps3av->av_port[i], |
345 | PS3AV_CMD_MUTE_ON); | 374 | PS3AV_CMD_MUTE_ON); |
346 | if (res < 0) | 375 | if (res < 0) |
347 | return -1; | 376 | return -1; |
@@ -350,11 +379,11 @@ static int ps3av_set_video_disable_sig(void) | |||
350 | 379 | ||
351 | /* video mute on */ | 380 | /* video mute on */ |
352 | for (i = 0; i < num_of_av_port; i++) { | 381 | for (i = 0; i < num_of_av_port; i++) { |
353 | res = ps3av_cmd_av_video_disable_sig(ps3av.av_port[i]); | 382 | res = ps3av_cmd_av_video_disable_sig(ps3av->av_port[i]); |
354 | if (res < 0) | 383 | if (res < 0) |
355 | return -1; | 384 | return -1; |
356 | if (i < num_of_hdmi_port) { | 385 | if (i < num_of_hdmi_port) { |
357 | res = ps3av_cmd_av_tv_mute(ps3av.av_port[i], | 386 | res = ps3av_cmd_av_tv_mute(ps3av->av_port[i], |
358 | PS3AV_CMD_MUTE_OFF); | 387 | PS3AV_CMD_MUTE_OFF); |
359 | if (res < 0) | 388 | if (res < 0) |
360 | return -1; | 389 | return -1; |
@@ -369,17 +398,17 @@ static int ps3av_set_audio_mute(u32 mute) | |||
369 | { | 398 | { |
370 | int i, num_of_av_port, num_of_opt_port, res; | 399 | int i, num_of_av_port, num_of_opt_port, res; |
371 | 400 | ||
372 | num_of_av_port = ps3av.av_hw_conf.num_of_hdmi + | 401 | num_of_av_port = ps3av->av_hw_conf.num_of_hdmi + |
373 | ps3av.av_hw_conf.num_of_avmulti; | 402 | ps3av->av_hw_conf.num_of_avmulti; |
374 | num_of_opt_port = ps3av.av_hw_conf.num_of_spdif; | 403 | num_of_opt_port = ps3av->av_hw_conf.num_of_spdif; |
375 | 404 | ||
376 | for (i = 0; i < num_of_av_port; i++) { | 405 | for (i = 0; i < num_of_av_port; i++) { |
377 | res = ps3av_cmd_av_audio_mute(1, &ps3av.av_port[i], mute); | 406 | res = ps3av_cmd_av_audio_mute(1, &ps3av->av_port[i], mute); |
378 | if (res < 0) | 407 | if (res < 0) |
379 | return -1; | 408 | return -1; |
380 | } | 409 | } |
381 | for (i = 0; i < num_of_opt_port; i++) { | 410 | for (i = 0; i < num_of_opt_port; i++) { |
382 | res = ps3av_cmd_audio_mute(1, &ps3av.opt_port[i], mute); | 411 | res = ps3av_cmd_audio_mute(1, &ps3av->opt_port[i], mute); |
383 | if (res < 0) | 412 | if (res < 0) |
384 | return -1; | 413 | return -1; |
385 | } | 414 | } |
@@ -394,40 +423,40 @@ int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source) | |||
394 | struct ps3av_pkt_audio_mode audio_mode; | 423 | struct ps3av_pkt_audio_mode audio_mode; |
395 | u32 len = 0; | 424 | u32 len = 0; |
396 | 425 | ||
397 | num_of_audio = ps3av.av_hw_conf.num_of_hdmi + | 426 | num_of_audio = ps3av->av_hw_conf.num_of_hdmi + |
398 | ps3av.av_hw_conf.num_of_avmulti + | 427 | ps3av->av_hw_conf.num_of_avmulti + |
399 | ps3av.av_hw_conf.num_of_spdif; | 428 | ps3av->av_hw_conf.num_of_spdif; |
400 | 429 | ||
401 | avb_param.num_of_video_pkt = 0; | 430 | avb_param.num_of_video_pkt = 0; |
402 | avb_param.num_of_audio_pkt = PS3AV_AVB_NUM_AUDIO; /* always 0 */ | 431 | avb_param.num_of_audio_pkt = PS3AV_AVB_NUM_AUDIO; /* always 0 */ |
403 | avb_param.num_of_av_video_pkt = 0; | 432 | avb_param.num_of_av_video_pkt = 0; |
404 | avb_param.num_of_av_audio_pkt = ps3av.av_hw_conf.num_of_hdmi; | 433 | avb_param.num_of_av_audio_pkt = ps3av->av_hw_conf.num_of_hdmi; |
405 | 434 | ||
406 | vid = video_mode_table[ps3av.ps3av_mode].vid; | 435 | vid = video_mode_table[ps3av->ps3av_mode].vid; |
407 | 436 | ||
408 | /* audio mute */ | 437 | /* audio mute */ |
409 | ps3av_set_audio_mute(PS3AV_CMD_MUTE_ON); | 438 | ps3av_set_audio_mute(PS3AV_CMD_MUTE_ON); |
410 | 439 | ||
411 | /* audio inactive */ | 440 | /* audio inactive */ |
412 | res = ps3av_cmd_audio_active(0, ps3av.audio_port); | 441 | res = ps3av_cmd_audio_active(0, ps3av->audio_port); |
413 | if (res < 0) | 442 | if (res < 0) |
414 | dev_dbg(&ps3av_dev.core, | 443 | dev_dbg(&ps3av->dev->core, |
415 | "ps3av_cmd_audio_active OFF failed\n"); | 444 | "ps3av_cmd_audio_active OFF failed\n"); |
416 | 445 | ||
417 | /* audio_pkt */ | 446 | /* audio_pkt */ |
418 | for (i = 0; i < num_of_audio; i++) { | 447 | for (i = 0; i < num_of_audio; i++) { |
419 | ps3av_cmd_set_audio_mode(&audio_mode, ps3av.av_port[i], ch, fs, | 448 | ps3av_cmd_set_audio_mode(&audio_mode, ps3av->av_port[i], ch, |
420 | word_bits, format, source); | 449 | fs, word_bits, format, source); |
421 | if (i < ps3av.av_hw_conf.num_of_hdmi) { | 450 | if (i < ps3av->av_hw_conf.num_of_hdmi) { |
422 | /* hdmi only */ | 451 | /* hdmi only */ |
423 | len += ps3av_cmd_set_av_audio_param(&avb_param.buf[len], | 452 | len += ps3av_cmd_set_av_audio_param(&avb_param.buf[len], |
424 | ps3av.av_port[i], | 453 | ps3av->av_port[i], |
425 | &audio_mode, vid); | 454 | &audio_mode, vid); |
426 | } | 455 | } |
427 | /* audio_mode pkt should be sent separately */ | 456 | /* audio_mode pkt should be sent separately */ |
428 | res = ps3av_cmd_audio_mode(&audio_mode); | 457 | res = ps3av_cmd_audio_mode(&audio_mode); |
429 | if (res < 0) | 458 | if (res < 0) |
430 | dev_dbg(&ps3av_dev.core, | 459 | dev_dbg(&ps3av->dev->core, |
431 | "ps3av_cmd_audio_mode failed, port:%x\n", i); | 460 | "ps3av_cmd_audio_mode failed, port:%x\n", i); |
432 | } | 461 | } |
433 | 462 | ||
@@ -435,15 +464,16 @@ int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source) | |||
435 | len += offsetof(struct ps3av_pkt_avb_param, buf); | 464 | len += offsetof(struct ps3av_pkt_avb_param, buf); |
436 | res = ps3av_cmd_avb_param(&avb_param, len); | 465 | res = ps3av_cmd_avb_param(&avb_param, len); |
437 | if (res < 0) | 466 | if (res < 0) |
438 | dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n"); | 467 | dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n"); |
439 | 468 | ||
440 | /* audio mute */ | 469 | /* audio mute */ |
441 | ps3av_set_audio_mute(PS3AV_CMD_MUTE_OFF); | 470 | ps3av_set_audio_mute(PS3AV_CMD_MUTE_OFF); |
442 | 471 | ||
443 | /* audio active */ | 472 | /* audio active */ |
444 | res = ps3av_cmd_audio_active(1, ps3av.audio_port); | 473 | res = ps3av_cmd_audio_active(1, ps3av->audio_port); |
445 | if (res < 0) | 474 | if (res < 0) |
446 | dev_dbg(&ps3av_dev.core, "ps3av_cmd_audio_active ON failed\n"); | 475 | dev_dbg(&ps3av->dev->core, |
476 | "ps3av_cmd_audio_active ON failed\n"); | ||
447 | 477 | ||
448 | return 0; | 478 | return 0; |
449 | } | 479 | } |
@@ -456,7 +486,7 @@ static int ps3av_set_videomode(void) | |||
456 | ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON); | 486 | ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON); |
457 | 487 | ||
458 | /* wake up ps3avd to do the actual video mode setting */ | 488 | /* wake up ps3avd to do the actual video mode setting */ |
459 | queue_work(ps3av.wq, &ps3av.work); | 489 | queue_work(ps3av->wq, &ps3av->work); |
460 | 490 | ||
461 | return 0; | 491 | return 0; |
462 | } | 492 | } |
@@ -473,8 +503,8 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id) | |||
473 | 503 | ||
474 | avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */ | 504 | avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */ |
475 | avb_param.num_of_audio_pkt = 0; | 505 | avb_param.num_of_audio_pkt = 0; |
476 | avb_param.num_of_av_video_pkt = ps3av.av_hw_conf.num_of_hdmi + | 506 | avb_param.num_of_av_video_pkt = ps3av->av_hw_conf.num_of_hdmi + |
477 | ps3av.av_hw_conf.num_of_avmulti; | 507 | ps3av->av_hw_conf.num_of_avmulti; |
478 | avb_param.num_of_av_audio_pkt = 0; | 508 | avb_param.num_of_av_audio_pkt = 0; |
479 | 509 | ||
480 | /* video signal off */ | 510 | /* video signal off */ |
@@ -484,21 +514,21 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id) | |||
484 | if (id & PS3AV_MODE_HDCP_OFF) { | 514 | if (id & PS3AV_MODE_HDCP_OFF) { |
485 | res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF); | 515 | res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF); |
486 | if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) | 516 | if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) |
487 | dev_dbg(&ps3av_dev.core, "Not supported\n"); | 517 | dev_dbg(&ps3av->dev->core, "Not supported\n"); |
488 | else if (res) | 518 | else if (res) |
489 | dev_dbg(&ps3av_dev.core, | 519 | dev_dbg(&ps3av->dev->core, |
490 | "ps3av_cmd_av_hdmi_mode failed\n"); | 520 | "ps3av_cmd_av_hdmi_mode failed\n"); |
491 | } else if (old_id & PS3AV_MODE_HDCP_OFF) { | 521 | } else if (old_id & PS3AV_MODE_HDCP_OFF) { |
492 | res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL); | 522 | res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL); |
493 | if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) | 523 | if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE) |
494 | dev_dbg(&ps3av_dev.core, | 524 | dev_dbg(&ps3av->dev->core, |
495 | "ps3av_cmd_av_hdmi_mode failed\n"); | 525 | "ps3av_cmd_av_hdmi_mode failed\n"); |
496 | } | 526 | } |
497 | 527 | ||
498 | /* video_pkt */ | 528 | /* video_pkt */ |
499 | for (i = 0; i < avb_param.num_of_video_pkt; i++) | 529 | for (i = 0; i < avb_param.num_of_video_pkt; i++) |
500 | len += ps3av_cmd_set_video_mode(&avb_param.buf[len], | 530 | len += ps3av_cmd_set_video_mode(&avb_param.buf[len], |
501 | ps3av.head[i], video_mode->vid, | 531 | ps3av->head[i], video_mode->vid, |
502 | video_mode->fmt, id); | 532 | video_mode->fmt, id); |
503 | /* av_video_pkt */ | 533 | /* av_video_pkt */ |
504 | for (i = 0; i < avb_param.num_of_av_video_pkt; i++) { | 534 | for (i = 0; i < avb_param.num_of_av_video_pkt; i++) { |
@@ -507,12 +537,12 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id) | |||
507 | else | 537 | else |
508 | av_video_cs = video_mode->cs; | 538 | av_video_cs = video_mode->cs; |
509 | #ifndef PS3AV_HDMI_YUV | 539 | #ifndef PS3AV_HDMI_YUV |
510 | if (ps3av.av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 || | 540 | if (ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 || |
511 | ps3av.av_port[i] == PS3AV_CMD_AVPORT_HDMI_1) | 541 | ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_1) |
512 | av_video_cs = RGB8; /* use RGB for HDMI */ | 542 | av_video_cs = RGB8; /* use RGB for HDMI */ |
513 | #endif | 543 | #endif |
514 | len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len], | 544 | len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len], |
515 | ps3av.av_port[i], | 545 | ps3av->av_port[i], |
516 | video_mode->vid, av_video_cs, | 546 | video_mode->vid, av_video_cs, |
517 | video_mode->aspect, id); | 547 | video_mode->aspect, id); |
518 | } | 548 | } |
@@ -524,7 +554,7 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id) | |||
524 | "%s: Command failed. Please try your request again. \n", | 554 | "%s: Command failed. Please try your request again. \n", |
525 | __func__); | 555 | __func__); |
526 | else if (res) | 556 | else if (res) |
527 | dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n"); | 557 | dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n"); |
528 | 558 | ||
529 | msleep(1500); | 559 | msleep(1500); |
530 | /* av video mute */ | 560 | /* av video mute */ |
@@ -533,8 +563,8 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id) | |||
533 | 563 | ||
534 | static void ps3avd(struct work_struct *work) | 564 | static void ps3avd(struct work_struct *work) |
535 | { | 565 | { |
536 | ps3av_set_videomode_cont(ps3av.ps3av_mode, ps3av.ps3av_mode_old); | 566 | ps3av_set_videomode_cont(ps3av->ps3av_mode, ps3av->ps3av_mode_old); |
537 | complete(&ps3av.done); | 567 | complete(&ps3av->done); |
538 | } | 568 | } |
539 | 569 | ||
540 | static int ps3av_vid2table_id(int vid) | 570 | static int ps3av_vid2table_id(int vid) |
@@ -601,7 +631,7 @@ static int ps3av_hdmi_get_vid(struct ps3av_info_monitor *info) | |||
601 | return vid; | 631 | return vid; |
602 | } | 632 | } |
603 | 633 | ||
604 | if (ps3av.region & PS3AV_REGION_60) | 634 | if (ps3av->region & PS3AV_REGION_60) |
605 | vid = PS3AV_DEFAULT_HDMI_VID_REG_60; | 635 | vid = PS3AV_DEFAULT_HDMI_VID_REG_60; |
606 | else | 636 | else |
607 | vid = PS3AV_DEFAULT_HDMI_VID_REG_50; | 637 | vid = PS3AV_DEFAULT_HDMI_VID_REG_50; |
@@ -643,16 +673,16 @@ static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf, | |||
643 | vid = PS3AV_DEFAULT_DVI_VID; | 673 | vid = PS3AV_DEFAULT_DVI_VID; |
644 | } else if (vid == -1) { | 674 | } else if (vid == -1) { |
645 | /* no HDMI interface or HDMI is off */ | 675 | /* no HDMI interface or HDMI is off */ |
646 | if (ps3av.region & PS3AV_REGION_60) | 676 | if (ps3av->region & PS3AV_REGION_60) |
647 | vid = PS3AV_DEFAULT_AVMULTI_VID_REG_60; | 677 | vid = PS3AV_DEFAULT_AVMULTI_VID_REG_60; |
648 | else | 678 | else |
649 | vid = PS3AV_DEFAULT_AVMULTI_VID_REG_50; | 679 | vid = PS3AV_DEFAULT_AVMULTI_VID_REG_50; |
650 | if (ps3av.region & PS3AV_REGION_RGB) | 680 | if (ps3av->region & PS3AV_REGION_RGB) |
651 | rgb = PS3AV_MODE_RGB; | 681 | rgb = PS3AV_MODE_RGB; |
652 | } else if (boot) { | 682 | } else if (boot) { |
653 | /* HDMI: using DEFAULT HDMI_VID while booting up */ | 683 | /* HDMI: using DEFAULT HDMI_VID while booting up */ |
654 | info = &monitor_info.info; | 684 | info = &monitor_info.info; |
655 | if (ps3av.region & PS3AV_REGION_60) { | 685 | if (ps3av->region & PS3AV_REGION_60) { |
656 | if (info->res_60.res_bits & PS3AV_RESBIT_720x480P) | 686 | if (info->res_60.res_bits & PS3AV_RESBIT_720x480P) |
657 | vid = PS3AV_DEFAULT_HDMI_VID_REG_60; | 687 | vid = PS3AV_DEFAULT_HDMI_VID_REG_60; |
658 | else if (info->res_50.res_bits & PS3AV_RESBIT_720x576P) | 688 | else if (info->res_50.res_bits & PS3AV_RESBIT_720x576P) |
@@ -715,14 +745,14 @@ int ps3av_set_video_mode(u32 id, int boot) | |||
715 | 745 | ||
716 | size = ARRAY_SIZE(video_mode_table); | 746 | size = ARRAY_SIZE(video_mode_table); |
717 | if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) { | 747 | if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) { |
718 | dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __func__, id); | 748 | dev_dbg(&ps3av->dev->core, "%s: error id :%d\n", __func__, id); |
719 | return -EINVAL; | 749 | return -EINVAL; |
720 | } | 750 | } |
721 | 751 | ||
722 | /* auto mode */ | 752 | /* auto mode */ |
723 | option = id & ~PS3AV_MODE_MASK; | 753 | option = id & ~PS3AV_MODE_MASK; |
724 | if ((id & PS3AV_MODE_MASK) == 0) { | 754 | if ((id & PS3AV_MODE_MASK) == 0) { |
725 | id = ps3av_auto_videomode(&ps3av.av_hw_conf, boot); | 755 | id = ps3av_auto_videomode(&ps3av->av_hw_conf, boot); |
726 | if (id < 1) { | 756 | if (id < 1) { |
727 | printk(KERN_ERR "%s: invalid id :%d\n", __func__, id); | 757 | printk(KERN_ERR "%s: invalid id :%d\n", __func__, id); |
728 | return -EINVAL; | 758 | return -EINVAL; |
@@ -731,11 +761,11 @@ int ps3av_set_video_mode(u32 id, int boot) | |||
731 | } | 761 | } |
732 | 762 | ||
733 | /* set videomode */ | 763 | /* set videomode */ |
734 | wait_for_completion(&ps3av.done); | 764 | wait_for_completion(&ps3av->done); |
735 | ps3av.ps3av_mode_old = ps3av.ps3av_mode; | 765 | ps3av->ps3av_mode_old = ps3av->ps3av_mode; |
736 | ps3av.ps3av_mode = id; | 766 | ps3av->ps3av_mode = id; |
737 | if (ps3av_set_videomode()) | 767 | if (ps3av_set_videomode()) |
738 | ps3av.ps3av_mode = ps3av.ps3av_mode_old; | 768 | ps3av->ps3av_mode = ps3av->ps3av_mode_old; |
739 | 769 | ||
740 | return 0; | 770 | return 0; |
741 | } | 771 | } |
@@ -744,7 +774,7 @@ EXPORT_SYMBOL_GPL(ps3av_set_video_mode); | |||
744 | 774 | ||
745 | int ps3av_get_auto_mode(int boot) | 775 | int ps3av_get_auto_mode(int boot) |
746 | { | 776 | { |
747 | return ps3av_auto_videomode(&ps3av.av_hw_conf, boot); | 777 | return ps3av_auto_videomode(&ps3av->av_hw_conf, boot); |
748 | } | 778 | } |
749 | 779 | ||
750 | EXPORT_SYMBOL_GPL(ps3av_get_auto_mode); | 780 | EXPORT_SYMBOL_GPL(ps3av_get_auto_mode); |
@@ -772,7 +802,7 @@ EXPORT_SYMBOL_GPL(ps3av_set_mode); | |||
772 | 802 | ||
773 | int ps3av_get_mode(void) | 803 | int ps3av_get_mode(void) |
774 | { | 804 | { |
775 | return ps3av.ps3av_mode; | 805 | return ps3av ? ps3av->ps3av_mode : 0; |
776 | } | 806 | } |
777 | 807 | ||
778 | EXPORT_SYMBOL_GPL(ps3av_get_mode); | 808 | EXPORT_SYMBOL_GPL(ps3av_get_mode); |
@@ -842,82 +872,65 @@ int ps3av_audio_mute(int mute) | |||
842 | 872 | ||
843 | EXPORT_SYMBOL_GPL(ps3av_audio_mute); | 873 | EXPORT_SYMBOL_GPL(ps3av_audio_mute); |
844 | 874 | ||
845 | int ps3av_dev_open(void) | 875 | void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data), |
876 | void *flip_data) | ||
846 | { | 877 | { |
847 | int status = 0; | 878 | mutex_lock(&ps3av->mutex); |
848 | 879 | ps3av->flip_ctl = flip_ctl; | |
849 | mutex_lock(&ps3av.mutex); | 880 | ps3av->flip_data = flip_data; |
850 | if (!ps3av.open_count++) { | 881 | mutex_unlock(&ps3av->mutex); |
851 | status = lv1_gpu_open(0); | ||
852 | if (status) { | ||
853 | printk(KERN_ERR "%s: lv1_gpu_open failed %d\n", | ||
854 | __func__, status); | ||
855 | ps3av.open_count--; | ||
856 | } | ||
857 | } | ||
858 | mutex_unlock(&ps3av.mutex); | ||
859 | |||
860 | return status; | ||
861 | } | 882 | } |
883 | EXPORT_SYMBOL_GPL(ps3av_register_flip_ctl); | ||
862 | 884 | ||
863 | EXPORT_SYMBOL_GPL(ps3av_dev_open); | 885 | void ps3av_flip_ctl(int on) |
864 | |||
865 | int ps3av_dev_close(void) | ||
866 | { | 886 | { |
867 | int status = 0; | 887 | mutex_lock(&ps3av->mutex); |
868 | 888 | if (ps3av->flip_ctl) | |
869 | mutex_lock(&ps3av.mutex); | 889 | ps3av->flip_ctl(on, ps3av->flip_data); |
870 | if (ps3av.open_count <= 0) { | 890 | mutex_unlock(&ps3av->mutex); |
871 | printk(KERN_ERR "%s: GPU already closed\n", __func__); | ||
872 | status = -1; | ||
873 | } else if (!--ps3av.open_count) { | ||
874 | status = lv1_gpu_close(); | ||
875 | if (status) | ||
876 | printk(KERN_WARNING "%s: lv1_gpu_close failed %d\n", | ||
877 | __func__, status); | ||
878 | } | ||
879 | mutex_unlock(&ps3av.mutex); | ||
880 | |||
881 | return status; | ||
882 | } | 891 | } |
883 | 892 | ||
884 | EXPORT_SYMBOL_GPL(ps3av_dev_close); | 893 | static int ps3av_probe(struct ps3_system_bus_device *dev) |
885 | |||
886 | static int ps3av_probe(struct ps3_vuart_port_device *dev) | ||
887 | { | 894 | { |
888 | int res; | 895 | int res; |
889 | u32 id; | 896 | u32 id; |
890 | 897 | ||
891 | dev_dbg(&ps3av_dev.core, "init ...\n"); | 898 | dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); |
892 | dev_dbg(&ps3av_dev.core, " timeout=%d\n", timeout); | 899 | dev_dbg(&dev->core, " timeout=%d\n", timeout); |
893 | 900 | ||
894 | memset(&ps3av, 0, sizeof(ps3av)); | 901 | if (ps3av) { |
895 | 902 | dev_err(&dev->core, "Only one ps3av device is supported\n"); | |
896 | mutex_init(&ps3av.mutex); | 903 | return -EBUSY; |
897 | ps3av.ps3av_mode = 0; | 904 | } |
898 | ps3av.dev = dev; | ||
899 | 905 | ||
900 | INIT_WORK(&ps3av.work, ps3avd); | 906 | ps3av = kzalloc(sizeof(*ps3av), GFP_KERNEL); |
901 | init_completion(&ps3av.done); | 907 | if (!ps3av) |
902 | complete(&ps3av.done); | ||
903 | ps3av.wq = create_singlethread_workqueue("ps3avd"); | ||
904 | if (!ps3av.wq) | ||
905 | return -ENOMEM; | 908 | return -ENOMEM; |
906 | 909 | ||
907 | ps3av.available = 1; | 910 | mutex_init(&ps3av->mutex); |
911 | ps3av->ps3av_mode = 0; | ||
912 | ps3av->dev = dev; | ||
913 | |||
914 | INIT_WORK(&ps3av->work, ps3avd); | ||
915 | init_completion(&ps3av->done); | ||
916 | complete(&ps3av->done); | ||
917 | ps3av->wq = create_singlethread_workqueue("ps3avd"); | ||
918 | if (!ps3av->wq) | ||
919 | goto fail; | ||
920 | |||
908 | switch (ps3_os_area_get_av_multi_out()) { | 921 | switch (ps3_os_area_get_av_multi_out()) { |
909 | case PS3_PARAM_AV_MULTI_OUT_NTSC: | 922 | case PS3_PARAM_AV_MULTI_OUT_NTSC: |
910 | ps3av.region = PS3AV_REGION_60; | 923 | ps3av->region = PS3AV_REGION_60; |
911 | break; | 924 | break; |
912 | case PS3_PARAM_AV_MULTI_OUT_PAL_YCBCR: | 925 | case PS3_PARAM_AV_MULTI_OUT_PAL_YCBCR: |
913 | case PS3_PARAM_AV_MULTI_OUT_SECAM: | 926 | case PS3_PARAM_AV_MULTI_OUT_SECAM: |
914 | ps3av.region = PS3AV_REGION_50; | 927 | ps3av->region = PS3AV_REGION_50; |
915 | break; | 928 | break; |
916 | case PS3_PARAM_AV_MULTI_OUT_PAL_RGB: | 929 | case PS3_PARAM_AV_MULTI_OUT_PAL_RGB: |
917 | ps3av.region = PS3AV_REGION_50 | PS3AV_REGION_RGB; | 930 | ps3av->region = PS3AV_REGION_50 | PS3AV_REGION_RGB; |
918 | break; | 931 | break; |
919 | default: | 932 | default: |
920 | ps3av.region = PS3AV_REGION_60; | 933 | ps3av->region = PS3AV_REGION_60; |
921 | break; | 934 | break; |
922 | } | 935 | } |
923 | 936 | ||
@@ -927,39 +940,47 @@ static int ps3av_probe(struct ps3_vuart_port_device *dev) | |||
927 | printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __func__, | 940 | printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __func__, |
928 | res); | 941 | res); |
929 | 942 | ||
930 | ps3av_get_hw_conf(&ps3av); | 943 | ps3av_get_hw_conf(ps3av); |
931 | id = ps3av_auto_videomode(&ps3av.av_hw_conf, 1); | 944 | id = ps3av_auto_videomode(&ps3av->av_hw_conf, 1); |
932 | mutex_lock(&ps3av.mutex); | 945 | mutex_lock(&ps3av->mutex); |
933 | ps3av.ps3av_mode = id; | 946 | ps3av->ps3av_mode = id; |
934 | mutex_unlock(&ps3av.mutex); | 947 | mutex_unlock(&ps3av->mutex); |
935 | 948 | ||
936 | dev_dbg(&ps3av_dev.core, "init...done\n"); | 949 | dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); |
937 | 950 | ||
938 | return 0; | 951 | return 0; |
952 | |||
953 | fail: | ||
954 | kfree(ps3av); | ||
955 | ps3av = NULL; | ||
956 | return -ENOMEM; | ||
939 | } | 957 | } |
940 | 958 | ||
941 | static int ps3av_remove(struct ps3_vuart_port_device *dev) | 959 | static int ps3av_remove(struct ps3_system_bus_device *dev) |
942 | { | 960 | { |
943 | if (ps3av.available) { | 961 | dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); |
962 | if (ps3av) { | ||
944 | ps3av_cmd_fin(); | 963 | ps3av_cmd_fin(); |
945 | if (ps3av.wq) | 964 | if (ps3av->wq) |
946 | destroy_workqueue(ps3av.wq); | 965 | destroy_workqueue(ps3av->wq); |
947 | ps3av.available = 0; | 966 | kfree(ps3av); |
967 | ps3av = NULL; | ||
948 | } | 968 | } |
949 | 969 | ||
970 | dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); | ||
950 | return 0; | 971 | return 0; |
951 | } | 972 | } |
952 | 973 | ||
953 | static void ps3av_shutdown(struct ps3_vuart_port_device *dev) | 974 | static void ps3av_shutdown(struct ps3_system_bus_device *dev) |
954 | { | 975 | { |
976 | dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); | ||
955 | ps3av_remove(dev); | 977 | ps3av_remove(dev); |
978 | dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); | ||
956 | } | 979 | } |
957 | 980 | ||
958 | static struct ps3_vuart_port_driver ps3av_driver = { | 981 | static struct ps3_vuart_port_driver ps3av_driver = { |
959 | .match_id = PS3_MATCH_ID_AV_SETTINGS, | 982 | .core.match_id = PS3_MATCH_ID_AV_SETTINGS, |
960 | .core = { | 983 | .core.core.name = "ps3_av", |
961 | .name = "ps3_av", | ||
962 | }, | ||
963 | .probe = ps3av_probe, | 984 | .probe = ps3av_probe, |
964 | .remove = ps3av_remove, | 985 | .remove = ps3av_remove, |
965 | .shutdown = ps3av_shutdown, | 986 | .shutdown = ps3av_shutdown, |
@@ -972,6 +993,8 @@ static int ps3av_module_init(void) | |||
972 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | 993 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) |
973 | return -ENODEV; | 994 | return -ENODEV; |
974 | 995 | ||
996 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
997 | |||
975 | error = ps3_vuart_port_driver_register(&ps3av_driver); | 998 | error = ps3_vuart_port_driver_register(&ps3av_driver); |
976 | if (error) { | 999 | if (error) { |
977 | printk(KERN_ERR | 1000 | printk(KERN_ERR |
@@ -980,20 +1003,21 @@ static int ps3av_module_init(void) | |||
980 | return error; | 1003 | return error; |
981 | } | 1004 | } |
982 | 1005 | ||
983 | error = ps3_vuart_port_device_register(&ps3av_dev); | 1006 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
984 | if (error) | ||
985 | printk(KERN_ERR | ||
986 | "%s: ps3_vuart_port_device_register failed %d\n", | ||
987 | __func__, error); | ||
988 | |||
989 | return error; | 1007 | return error; |
990 | } | 1008 | } |
991 | 1009 | ||
992 | static void __exit ps3av_module_exit(void) | 1010 | static void __exit ps3av_module_exit(void) |
993 | { | 1011 | { |
994 | device_unregister(&ps3av_dev.core); | 1012 | pr_debug(" -> %s:%d\n", __func__, __LINE__); |
995 | ps3_vuart_port_driver_unregister(&ps3av_driver); | 1013 | ps3_vuart_port_driver_unregister(&ps3av_driver); |
1014 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
996 | } | 1015 | } |
997 | 1016 | ||
998 | subsys_initcall(ps3av_module_init); | 1017 | subsys_initcall(ps3av_module_init); |
999 | module_exit(ps3av_module_exit); | 1018 | module_exit(ps3av_module_exit); |
1019 | |||
1020 | MODULE_LICENSE("GPL v2"); | ||
1021 | MODULE_DESCRIPTION("PS3 AV Settings Driver"); | ||
1022 | MODULE_AUTHOR("Sony Computer Entertainment Inc."); | ||
1023 | MODULE_ALIAS(PS3_MODULE_ALIAS_AV_SETTINGS); | ||
diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c index 0145ea173c42..f72f5ddf18e4 100644 --- a/drivers/ps3/ps3av_cmd.c +++ b/drivers/ps3/ps3av_cmd.c | |||
@@ -143,6 +143,14 @@ static u32 ps3av_vid_video2av(int vid) | |||
143 | return PS3AV_CMD_AV_VID_480P; | 143 | return PS3AV_CMD_AV_VID_480P; |
144 | } | 144 | } |
145 | 145 | ||
146 | static int ps3av_hdmi_range(void) | ||
147 | { | ||
148 | if (ps3_compare_firmware_version(1, 8, 0) < 0) | ||
149 | return 0; | ||
150 | else | ||
151 | return 1; /* supported */ | ||
152 | } | ||
153 | |||
146 | int ps3av_cmd_init(void) | 154 | int ps3av_cmd_init(void) |
147 | { | 155 | { |
148 | int res; | 156 | int res; |
@@ -350,6 +358,10 @@ u32 ps3av_cmd_set_av_video_cs(void *p, u32 avport, int video_vid, int cs_out, | |||
350 | /* should be same as video_mode.video_cs_out */ | 358 | /* should be same as video_mode.video_cs_out */ |
351 | av_video_cs->av_cs_in = ps3av_cs_video2av(PS3AV_CMD_VIDEO_CS_RGB_8); | 359 | av_video_cs->av_cs_in = ps3av_cs_video2av(PS3AV_CMD_VIDEO_CS_RGB_8); |
352 | av_video_cs->bitlen_out = ps3av_cs_video2av_bitlen(cs_out); | 360 | av_video_cs->bitlen_out = ps3av_cs_video2av_bitlen(cs_out); |
361 | if ((id & PS3AV_MODE_WHITE) && ps3av_hdmi_range()) | ||
362 | av_video_cs->super_white = PS3AV_CMD_AV_SUPER_WHITE_ON; | ||
363 | else /* default off */ | ||
364 | av_video_cs->super_white = PS3AV_CMD_AV_SUPER_WHITE_OFF; | ||
353 | av_video_cs->aspect = aspect; | 365 | av_video_cs->aspect = aspect; |
354 | if (id & PS3AV_MODE_DITHER) { | 366 | if (id & PS3AV_MODE_DITHER) { |
355 | av_video_cs->dither = PS3AV_CMD_AV_DITHER_ON | 367 | av_video_cs->dither = PS3AV_CMD_AV_DITHER_ON |
@@ -392,6 +404,10 @@ u32 ps3av_cmd_set_video_mode(void *p, u32 head, int video_vid, int video_fmt, | |||
392 | video_mode->pitch = video_mode->width * 4; /* line_length */ | 404 | video_mode->pitch = video_mode->width * 4; /* line_length */ |
393 | video_mode->video_out_format = PS3AV_CMD_VIDEO_OUT_FORMAT_RGB_12BIT; | 405 | video_mode->video_out_format = PS3AV_CMD_VIDEO_OUT_FORMAT_RGB_12BIT; |
394 | video_mode->video_format = ps3av_video_fmt_table[video_fmt].format; | 406 | video_mode->video_format = ps3av_video_fmt_table[video_fmt].format; |
407 | if ((id & PS3AV_MODE_COLOR) && ps3av_hdmi_range()) | ||
408 | video_mode->video_cl_cnv = PS3AV_CMD_VIDEO_CL_CNV_DISABLE_LUT; | ||
409 | else /* default enable */ | ||
410 | video_mode->video_cl_cnv = PS3AV_CMD_VIDEO_CL_CNV_ENABLE_LUT; | ||
395 | video_mode->video_order = ps3av_video_fmt_table[video_fmt].order; | 411 | video_mode->video_order = ps3av_video_fmt_table[video_fmt].order; |
396 | 412 | ||
397 | pr_debug("%s: video_mode:vid:%x width:%d height:%d pitch:%d out_format:%d format:%x order:%x\n", | 413 | pr_debug("%s: video_mode:vid:%x width:%d height:%d pitch:%d out_format:%d format:%x order:%x\n", |
@@ -852,7 +868,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len) | |||
852 | { | 868 | { |
853 | int res; | 869 | int res; |
854 | 870 | ||
855 | ps3fb_flip_ctl(0); /* flip off */ | 871 | ps3av_flip_ctl(0); /* flip off */ |
856 | 872 | ||
857 | /* avb packet */ | 873 | /* avb packet */ |
858 | res = ps3av_do_pkt(PS3AV_CID_AVB_PARAM, send_len, sizeof(*avb), | 874 | res = ps3av_do_pkt(PS3AV_CID_AVB_PARAM, send_len, sizeof(*avb), |
@@ -866,7 +882,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len) | |||
866 | res); | 882 | res); |
867 | 883 | ||
868 | out: | 884 | out: |
869 | ps3fb_flip_ctl(1); /* flip on */ | 885 | ps3av_flip_ctl(1); /* flip on */ |
870 | return res; | 886 | return res; |
871 | } | 887 | } |
872 | 888 | ||
@@ -987,34 +1003,3 @@ void ps3av_cmd_av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info * | |||
987 | | PS3AV_CMD_AV_LAYOUT_176 \ | 1003 | | PS3AV_CMD_AV_LAYOUT_176 \ |
988 | | PS3AV_CMD_AV_LAYOUT_192) | 1004 | | PS3AV_CMD_AV_LAYOUT_192) |
989 | 1005 | ||
990 | /************************* vuart ***************************/ | ||
991 | |||
992 | #define POLLING_INTERVAL 25 /* in msec */ | ||
993 | |||
994 | int ps3av_vuart_write(struct ps3_vuart_port_device *dev, const void *buf, | ||
995 | unsigned long size) | ||
996 | { | ||
997 | int error = ps3_vuart_write(dev, buf, size); | ||
998 | return error ? error : size; | ||
999 | } | ||
1000 | |||
1001 | int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf, | ||
1002 | unsigned long size, int timeout) | ||
1003 | { | ||
1004 | int error; | ||
1005 | int loopcnt = 0; | ||
1006 | |||
1007 | timeout = (timeout + POLLING_INTERVAL - 1) / POLLING_INTERVAL; | ||
1008 | while (loopcnt++ <= timeout) { | ||
1009 | error = ps3_vuart_read(dev, buf, size); | ||
1010 | if (!error) | ||
1011 | return size; | ||
1012 | if (error != -EAGAIN) { | ||
1013 | printk(KERN_ERR "%s: ps3_vuart_read failed %d\n", | ||
1014 | __func__, error); | ||
1015 | return error; | ||
1016 | } | ||
1017 | msleep(POLLING_INTERVAL); | ||
1018 | } | ||
1019 | return -EWOULDBLOCK; | ||
1020 | } | ||
diff --git a/drivers/ps3/ps3stor_lib.c b/drivers/ps3/ps3stor_lib.c new file mode 100644 index 000000000000..3a9824e3b251 --- /dev/null +++ b/drivers/ps3/ps3stor_lib.c | |||
@@ -0,0 +1,302 @@ | |||
1 | /* | ||
2 | * PS3 Storage Library | ||
3 | * | ||
4 | * Copyright (C) 2007 Sony Computer Entertainment Inc. | ||
5 | * Copyright 2007 Sony Corp. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published | ||
9 | * by the Free Software Foundation; version 2 of the License. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/dma-mapping.h> | ||
22 | |||
23 | #include <asm/lv1call.h> | ||
24 | #include <asm/ps3stor.h> | ||
25 | |||
26 | |||
27 | static int ps3stor_probe_access(struct ps3_storage_device *dev) | ||
28 | { | ||
29 | int res, error; | ||
30 | unsigned int i; | ||
31 | unsigned long n; | ||
32 | |||
33 | if (dev->sbd.match_id == PS3_MATCH_ID_STOR_ROM) { | ||
34 | /* special case: CD-ROM is assumed always accessible */ | ||
35 | dev->accessible_regions = 1; | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | error = -EPERM; | ||
40 | for (i = 0; i < dev->num_regions; i++) { | ||
41 | dev_dbg(&dev->sbd.core, | ||
42 | "%s:%u: checking accessibility of region %u\n", | ||
43 | __func__, __LINE__, i); | ||
44 | |||
45 | dev->region_idx = i; | ||
46 | res = ps3stor_read_write_sectors(dev, dev->bounce_lpar, 0, 1, | ||
47 | 0); | ||
48 | if (res) { | ||
49 | dev_dbg(&dev->sbd.core, "%s:%u: read failed, " | ||
50 | "region %u is not accessible\n", __func__, | ||
51 | __LINE__, i); | ||
52 | continue; | ||
53 | } | ||
54 | |||
55 | dev_dbg(&dev->sbd.core, "%s:%u: region %u is accessible\n", | ||
56 | __func__, __LINE__, i); | ||
57 | set_bit(i, &dev->accessible_regions); | ||
58 | |||
59 | /* We can access at least one region */ | ||
60 | error = 0; | ||
61 | } | ||
62 | if (error) | ||
63 | return error; | ||
64 | |||
65 | n = hweight_long(dev->accessible_regions); | ||
66 | if (n > 1) | ||
67 | dev_info(&dev->sbd.core, | ||
68 | "%s:%u: %lu accessible regions found. Only the first " | ||
69 | "one will be used", | ||
70 | __func__, __LINE__, n); | ||
71 | dev->region_idx = __ffs(dev->accessible_regions); | ||
72 | dev_info(&dev->sbd.core, | ||
73 | "First accessible region has index %u start %lu size %lu\n", | ||
74 | dev->region_idx, dev->regions[dev->region_idx].start, | ||
75 | dev->regions[dev->region_idx].size); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | |||
81 | /** | ||
82 | * ps3stor_setup - Setup a storage device before use | ||
83 | * @dev: Pointer to a struct ps3_storage_device | ||
84 | * @handler: Pointer to an interrupt handler | ||
85 | * | ||
86 | * Returns 0 for success, or an error code | ||
87 | */ | ||
88 | int ps3stor_setup(struct ps3_storage_device *dev, irq_handler_t handler) | ||
89 | { | ||
90 | int error, res, alignment; | ||
91 | enum ps3_dma_page_size page_size; | ||
92 | |||
93 | error = ps3_open_hv_device(&dev->sbd); | ||
94 | if (error) { | ||
95 | dev_err(&dev->sbd.core, | ||
96 | "%s:%u: ps3_open_hv_device failed %d\n", __func__, | ||
97 | __LINE__, error); | ||
98 | goto fail; | ||
99 | } | ||
100 | |||
101 | error = ps3_sb_event_receive_port_setup(&dev->sbd, PS3_BINDING_CPU_ANY, | ||
102 | &dev->irq); | ||
103 | if (error) { | ||
104 | dev_err(&dev->sbd.core, | ||
105 | "%s:%u: ps3_sb_event_receive_port_setup failed %d\n", | ||
106 | __func__, __LINE__, error); | ||
107 | goto fail_close_device; | ||
108 | } | ||
109 | |||
110 | error = request_irq(dev->irq, handler, IRQF_DISABLED, | ||
111 | dev->sbd.core.driver->name, dev); | ||
112 | if (error) { | ||
113 | dev_err(&dev->sbd.core, "%s:%u: request_irq failed %d\n", | ||
114 | __func__, __LINE__, error); | ||
115 | goto fail_sb_event_receive_port_destroy; | ||
116 | } | ||
117 | |||
118 | alignment = min(__ffs(dev->bounce_size), | ||
119 | __ffs((unsigned long)dev->bounce_buf)); | ||
120 | if (alignment < 12) { | ||
121 | dev_err(&dev->sbd.core, | ||
122 | "%s:%u: bounce buffer not aligned (%lx at 0x%p)\n", | ||
123 | __func__, __LINE__, dev->bounce_size, dev->bounce_buf); | ||
124 | error = -EINVAL; | ||
125 | goto fail_free_irq; | ||
126 | } else if (alignment < 16) | ||
127 | page_size = PS3_DMA_4K; | ||
128 | else | ||
129 | page_size = PS3_DMA_64K; | ||
130 | dev->sbd.d_region = &dev->dma_region; | ||
131 | ps3_dma_region_init(&dev->sbd, &dev->dma_region, page_size, | ||
132 | PS3_DMA_OTHER, dev->bounce_buf, dev->bounce_size); | ||
133 | res = ps3_dma_region_create(&dev->dma_region); | ||
134 | if (res) { | ||
135 | dev_err(&dev->sbd.core, "%s:%u: cannot create DMA region\n", | ||
136 | __func__, __LINE__); | ||
137 | error = -ENOMEM; | ||
138 | goto fail_free_irq; | ||
139 | } | ||
140 | |||
141 | dev->bounce_lpar = ps3_mm_phys_to_lpar(__pa(dev->bounce_buf)); | ||
142 | dev->bounce_dma = dma_map_single(&dev->sbd.core, dev->bounce_buf, | ||
143 | dev->bounce_size, DMA_BIDIRECTIONAL); | ||
144 | if (!dev->bounce_dma) { | ||
145 | dev_err(&dev->sbd.core, "%s:%u: map DMA region failed\n", | ||
146 | __func__, __LINE__); | ||
147 | error = -ENODEV; | ||
148 | goto fail_free_dma; | ||
149 | } | ||
150 | |||
151 | error = ps3stor_probe_access(dev); | ||
152 | if (error) { | ||
153 | dev_err(&dev->sbd.core, "%s:%u: No accessible regions found\n", | ||
154 | __func__, __LINE__); | ||
155 | goto fail_unmap_dma; | ||
156 | } | ||
157 | return 0; | ||
158 | |||
159 | fail_unmap_dma: | ||
160 | dma_unmap_single(&dev->sbd.core, dev->bounce_dma, dev->bounce_size, | ||
161 | DMA_BIDIRECTIONAL); | ||
162 | fail_free_dma: | ||
163 | ps3_dma_region_free(&dev->dma_region); | ||
164 | fail_free_irq: | ||
165 | free_irq(dev->irq, dev); | ||
166 | fail_sb_event_receive_port_destroy: | ||
167 | ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq); | ||
168 | fail_close_device: | ||
169 | ps3_close_hv_device(&dev->sbd); | ||
170 | fail: | ||
171 | return error; | ||
172 | } | ||
173 | EXPORT_SYMBOL_GPL(ps3stor_setup); | ||
174 | |||
175 | |||
176 | /** | ||
177 | * ps3stor_teardown - Tear down a storage device after use | ||
178 | * @dev: Pointer to a struct ps3_storage_device | ||
179 | */ | ||
180 | void ps3stor_teardown(struct ps3_storage_device *dev) | ||
181 | { | ||
182 | int error; | ||
183 | |||
184 | dma_unmap_single(&dev->sbd.core, dev->bounce_dma, dev->bounce_size, | ||
185 | DMA_BIDIRECTIONAL); | ||
186 | ps3_dma_region_free(&dev->dma_region); | ||
187 | |||
188 | free_irq(dev->irq, dev); | ||
189 | |||
190 | error = ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq); | ||
191 | if (error) | ||
192 | dev_err(&dev->sbd.core, | ||
193 | "%s:%u: destroy event receive port failed %d\n", | ||
194 | __func__, __LINE__, error); | ||
195 | |||
196 | error = ps3_close_hv_device(&dev->sbd); | ||
197 | if (error) | ||
198 | dev_err(&dev->sbd.core, | ||
199 | "%s:%u: ps3_close_hv_device failed %d\n", __func__, | ||
200 | __LINE__, error); | ||
201 | } | ||
202 | EXPORT_SYMBOL_GPL(ps3stor_teardown); | ||
203 | |||
204 | |||
205 | /** | ||
206 | * ps3stor_read_write_sectors - read/write from/to a storage device | ||
207 | * @dev: Pointer to a struct ps3_storage_device | ||
208 | * @lpar: HV logical partition address | ||
209 | * @start_sector: First sector to read/write | ||
210 | * @sectors: Number of sectors to read/write | ||
211 | * @write: Flag indicating write (non-zero) or read (zero) | ||
212 | * | ||
213 | * Returns 0 for success, -1 in case of failure to submit the command, or | ||
214 | * an LV1 status value in case of other errors | ||
215 | */ | ||
216 | u64 ps3stor_read_write_sectors(struct ps3_storage_device *dev, u64 lpar, | ||
217 | u64 start_sector, u64 sectors, int write) | ||
218 | { | ||
219 | unsigned int region_id = dev->regions[dev->region_idx].id; | ||
220 | const char *op = write ? "write" : "read"; | ||
221 | int res; | ||
222 | |||
223 | dev_dbg(&dev->sbd.core, "%s:%u: %s %lu sectors starting at %lu\n", | ||
224 | __func__, __LINE__, op, sectors, start_sector); | ||
225 | |||
226 | init_completion(&dev->done); | ||
227 | res = write ? lv1_storage_write(dev->sbd.dev_id, region_id, | ||
228 | start_sector, sectors, 0, lpar, | ||
229 | &dev->tag) | ||
230 | : lv1_storage_read(dev->sbd.dev_id, region_id, | ||
231 | start_sector, sectors, 0, lpar, | ||
232 | &dev->tag); | ||
233 | if (res) { | ||
234 | dev_dbg(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__, | ||
235 | __LINE__, op, res); | ||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | wait_for_completion(&dev->done); | ||
240 | if (dev->lv1_status) { | ||
241 | dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__, | ||
242 | __LINE__, op, dev->lv1_status); | ||
243 | return dev->lv1_status; | ||
244 | } | ||
245 | |||
246 | dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__, __LINE__, | ||
247 | op); | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | EXPORT_SYMBOL_GPL(ps3stor_read_write_sectors); | ||
252 | |||
253 | |||
254 | /** | ||
255 | * ps3stor_send_command - send a device command to a storage device | ||
256 | * @dev: Pointer to a struct ps3_storage_device | ||
257 | * @cmd: Command number | ||
258 | * @arg1: First command argument | ||
259 | * @arg2: Second command argument | ||
260 | * @arg3: Third command argument | ||
261 | * @arg4: Fourth command argument | ||
262 | * | ||
263 | * Returns 0 for success, -1 in case of failure to submit the command, or | ||
264 | * an LV1 status value in case of other errors | ||
265 | */ | ||
266 | u64 ps3stor_send_command(struct ps3_storage_device *dev, u64 cmd, u64 arg1, | ||
267 | u64 arg2, u64 arg3, u64 arg4) | ||
268 | { | ||
269 | int res; | ||
270 | |||
271 | dev_dbg(&dev->sbd.core, "%s:%u: send device command 0x%lx\n", __func__, | ||
272 | __LINE__, cmd); | ||
273 | |||
274 | init_completion(&dev->done); | ||
275 | |||
276 | res = lv1_storage_send_device_command(dev->sbd.dev_id, cmd, arg1, | ||
277 | arg2, arg3, arg4, &dev->tag); | ||
278 | if (res) { | ||
279 | dev_err(&dev->sbd.core, | ||
280 | "%s:%u: send_device_command 0x%lx failed %d\n", | ||
281 | __func__, __LINE__, cmd, res); | ||
282 | return -1; | ||
283 | } | ||
284 | |||
285 | wait_for_completion(&dev->done); | ||
286 | if (dev->lv1_status) { | ||
287 | dev_dbg(&dev->sbd.core, "%s:%u: command 0x%lx failed 0x%lx\n", | ||
288 | __func__, __LINE__, cmd, dev->lv1_status); | ||
289 | return dev->lv1_status; | ||
290 | } | ||
291 | |||
292 | dev_dbg(&dev->sbd.core, "%s:%u: command 0x%lx completed\n", __func__, | ||
293 | __LINE__, cmd); | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | EXPORT_SYMBOL_GPL(ps3stor_send_command); | ||
298 | |||
299 | |||
300 | MODULE_LICENSE("GPL"); | ||
301 | MODULE_DESCRIPTION("PS3 Storage Bus Library"); | ||
302 | MODULE_AUTHOR("Sony Corporation"); | ||
diff --git a/drivers/ps3/sys-manager-core.c b/drivers/ps3/sys-manager-core.c new file mode 100644 index 000000000000..31648f7d9ae1 --- /dev/null +++ b/drivers/ps3/sys-manager-core.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * PS3 System Manager core. | ||
3 | * | ||
4 | * Copyright (C) 2007 Sony Computer Entertainment Inc. | ||
5 | * Copyright 2007 Sony Corp. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; version 2 of the License. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <asm/ps3.h> | ||
23 | |||
24 | /** | ||
25 | * Staticly linked routines that allow late binding of a loaded sys-manager | ||
26 | * module. | ||
27 | */ | ||
28 | |||
29 | static struct ps3_sys_manager_ops ps3_sys_manager_ops; | ||
30 | |||
31 | /** | ||
32 | * ps3_register_sys_manager_ops - Bind ps3_sys_manager_ops to a module. | ||
33 | * @ops: struct ps3_sys_manager_ops. | ||
34 | * | ||
35 | * To be called from ps3_sys_manager_probe() and ps3_sys_manager_remove() to | ||
36 | * register call back ops for power control. Copies data to the static | ||
37 | * variable ps3_sys_manager_ops. | ||
38 | */ | ||
39 | |||
40 | void ps3_sys_manager_register_ops(const struct ps3_sys_manager_ops *ops) | ||
41 | { | ||
42 | BUG_ON(!ops); | ||
43 | BUG_ON(!ops->dev); | ||
44 | ps3_sys_manager_ops = ops ? *ops : ps3_sys_manager_ops; | ||
45 | } | ||
46 | EXPORT_SYMBOL_GPL(ps3_sys_manager_register_ops); | ||
47 | |||
48 | void ps3_sys_manager_power_off(void) | ||
49 | { | ||
50 | if (ps3_sys_manager_ops.power_off) | ||
51 | ps3_sys_manager_ops.power_off(ps3_sys_manager_ops.dev); | ||
52 | |||
53 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); | ||
54 | local_irq_disable(); | ||
55 | while (1) | ||
56 | (void)0; | ||
57 | } | ||
58 | |||
59 | void ps3_sys_manager_restart(void) | ||
60 | { | ||
61 | if (ps3_sys_manager_ops.restart) | ||
62 | ps3_sys_manager_ops.restart(ps3_sys_manager_ops.dev); | ||
63 | |||
64 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); | ||
65 | local_irq_disable(); | ||
66 | while (1) | ||
67 | (void)0; | ||
68 | } | ||
diff --git a/drivers/ps3/sys-manager.c b/drivers/ps3/sys-manager.c index 3aa2b0dcc369..8461b08ab9fb 100644 --- a/drivers/ps3/sys-manager.c +++ b/drivers/ps3/sys-manager.c | |||
@@ -35,7 +35,7 @@ MODULE_DESCRIPTION("PS3 System Manager"); | |||
35 | /** | 35 | /** |
36 | * ps3_sys_manager - PS3 system manager driver. | 36 | * ps3_sys_manager - PS3 system manager driver. |
37 | * | 37 | * |
38 | * The system manager provides an asyncronous system event notification | 38 | * The system manager provides an asynchronous system event notification |
39 | * mechanism for reporting events like thermal alert and button presses to | 39 | * mechanism for reporting events like thermal alert and button presses to |
40 | * guests. It also provides support to control system shutdown and startup. | 40 | * guests. It also provides support to control system shutdown and startup. |
41 | * | 41 | * |
@@ -52,6 +52,7 @@ MODULE_DESCRIPTION("PS3 System Manager"); | |||
52 | * @size: Header size in bytes, curently 16. | 52 | * @size: Header size in bytes, curently 16. |
53 | * @payload_size: Message payload size in bytes. | 53 | * @payload_size: Message payload size in bytes. |
54 | * @service_id: Message type, one of enum ps3_sys_manager_service_id. | 54 | * @service_id: Message type, one of enum ps3_sys_manager_service_id. |
55 | * @request_tag: Unique number to identify reply. | ||
55 | */ | 56 | */ |
56 | 57 | ||
57 | struct ps3_sys_manager_header { | 58 | struct ps3_sys_manager_header { |
@@ -61,29 +62,49 @@ struct ps3_sys_manager_header { | |||
61 | u16 reserved_1; | 62 | u16 reserved_1; |
62 | u32 payload_size; | 63 | u32 payload_size; |
63 | u16 service_id; | 64 | u16 service_id; |
64 | u16 reserved_2[3]; | 65 | u16 reserved_2; |
66 | u32 request_tag; | ||
65 | }; | 67 | }; |
66 | 68 | ||
69 | #define dump_sm_header(_h) _dump_sm_header(_h, __func__, __LINE__) | ||
70 | static void __maybe_unused _dump_sm_header( | ||
71 | const struct ps3_sys_manager_header *h, const char *func, int line) | ||
72 | { | ||
73 | pr_debug("%s:%d: version: %xh\n", func, line, h->version); | ||
74 | pr_debug("%s:%d: size: %xh\n", func, line, h->size); | ||
75 | pr_debug("%s:%d: payload_size: %xh\n", func, line, h->payload_size); | ||
76 | pr_debug("%s:%d: service_id: %xh\n", func, line, h->service_id); | ||
77 | pr_debug("%s:%d: request_tag: %xh\n", func, line, h->request_tag); | ||
78 | } | ||
79 | |||
67 | /** | 80 | /** |
68 | * @PS3_SM_RX_MSG_LEN - System manager received message length. | 81 | * @PS3_SM_RX_MSG_LEN_MIN - Shortest received message length. |
82 | * @PS3_SM_RX_MSG_LEN_MAX - Longest received message length. | ||
69 | * | 83 | * |
70 | * Currently all messages received from the system manager are the same length | 84 | * Currently all messages received from the system manager are either |
71 | * (16 bytes header + 16 bytes payload = 32 bytes). This knowlege is used to | 85 | * (16 bytes header + 8 bytes payload = 24 bytes) or (16 bytes header |
72 | * simplify the logic. | 86 | * + 16 bytes payload = 32 bytes). This knowlege is used to simplify |
87 | * the logic. | ||
73 | */ | 88 | */ |
74 | 89 | ||
75 | enum { | 90 | enum { |
76 | PS3_SM_RX_MSG_LEN = 32, | 91 | PS3_SM_RX_MSG_LEN_MIN = 24, |
92 | PS3_SM_RX_MSG_LEN_MAX = 32, | ||
77 | }; | 93 | }; |
78 | 94 | ||
79 | /** | 95 | /** |
80 | * enum ps3_sys_manager_service_id - Message header service_id. | 96 | * enum ps3_sys_manager_service_id - Message header service_id. |
81 | * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager. | 97 | * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager. |
82 | * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager. | 98 | * @PS3_SM_SERVICE_ID_REQUEST_ERROR: guest <-- sys_manager. |
83 | * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager. | 99 | * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager. |
84 | * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager. | 100 | * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager. |
85 | * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager. | 101 | * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager. |
86 | * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager. | 102 | * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager. |
103 | * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager. | ||
104 | * | ||
105 | * PS3_SM_SERVICE_ID_REQUEST_ERROR is returned for invalid data values in a | ||
106 | * a PS3_SM_SERVICE_ID_REQUEST message. It also seems to be returned when | ||
107 | * a REQUEST message is sent at the wrong time. | ||
87 | */ | 108 | */ |
88 | 109 | ||
89 | enum ps3_sys_manager_service_id { | 110 | enum ps3_sys_manager_service_id { |
@@ -93,6 +114,7 @@ enum ps3_sys_manager_service_id { | |||
93 | PS3_SM_SERVICE_ID_COMMAND = 3, | 114 | PS3_SM_SERVICE_ID_COMMAND = 3, |
94 | PS3_SM_SERVICE_ID_EXTERN_EVENT = 4, | 115 | PS3_SM_SERVICE_ID_EXTERN_EVENT = 4, |
95 | PS3_SM_SERVICE_ID_SET_NEXT_OP = 5, | 116 | PS3_SM_SERVICE_ID_SET_NEXT_OP = 5, |
117 | PS3_SM_SERVICE_ID_REQUEST_ERROR = 6, | ||
96 | PS3_SM_SERVICE_ID_SET_ATTR = 8, | 118 | PS3_SM_SERVICE_ID_SET_ATTR = 8, |
97 | }; | 119 | }; |
98 | 120 | ||
@@ -185,11 +207,21 @@ enum ps3_sys_manager_cmd { | |||
185 | }; | 207 | }; |
186 | 208 | ||
187 | /** | 209 | /** |
210 | * ps3_sm_force_power_off - Poweroff helper. | ||
211 | * | ||
212 | * A global variable used to force a poweroff when the power button has | ||
213 | * been pressed irrespective of how init handles the ctrl_alt_del signal. | ||
214 | * | ||
215 | */ | ||
216 | |||
217 | static unsigned int ps3_sm_force_power_off; | ||
218 | |||
219 | /** | ||
188 | * ps3_sys_manager_write - Helper to write a two part message to the vuart. | 220 | * ps3_sys_manager_write - Helper to write a two part message to the vuart. |
189 | * | 221 | * |
190 | */ | 222 | */ |
191 | 223 | ||
192 | static int ps3_sys_manager_write(struct ps3_vuart_port_device *dev, | 224 | static int ps3_sys_manager_write(struct ps3_system_bus_device *dev, |
193 | const struct ps3_sys_manager_header *header, const void *payload) | 225 | const struct ps3_sys_manager_header *header, const void *payload) |
194 | { | 226 | { |
195 | int result; | 227 | int result; |
@@ -213,15 +245,10 @@ static int ps3_sys_manager_write(struct ps3_vuart_port_device *dev, | |||
213 | * | 245 | * |
214 | */ | 246 | */ |
215 | 247 | ||
216 | static int ps3_sys_manager_send_attr(struct ps3_vuart_port_device *dev, | 248 | static int ps3_sys_manager_send_attr(struct ps3_system_bus_device *dev, |
217 | enum ps3_sys_manager_attr attr) | 249 | enum ps3_sys_manager_attr attr) |
218 | { | 250 | { |
219 | static const struct ps3_sys_manager_header header = { | 251 | struct ps3_sys_manager_header header; |
220 | .version = 1, | ||
221 | .size = 16, | ||
222 | .payload_size = 16, | ||
223 | .service_id = PS3_SM_SERVICE_ID_SET_ATTR, | ||
224 | }; | ||
225 | struct { | 252 | struct { |
226 | u8 version; | 253 | u8 version; |
227 | u8 reserved_1[3]; | 254 | u8 reserved_1[3]; |
@@ -232,6 +259,12 @@ static int ps3_sys_manager_send_attr(struct ps3_vuart_port_device *dev, | |||
232 | 259 | ||
233 | dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr); | 260 | dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr); |
234 | 261 | ||
262 | memset(&header, 0, sizeof(header)); | ||
263 | header.version = 1; | ||
264 | header.size = 16; | ||
265 | header.payload_size = 16; | ||
266 | header.service_id = PS3_SM_SERVICE_ID_SET_ATTR; | ||
267 | |||
235 | memset(&payload, 0, sizeof(payload)); | 268 | memset(&payload, 0, sizeof(payload)); |
236 | payload.version = 1; | 269 | payload.version = 1; |
237 | payload.attribute = attr; | 270 | payload.attribute = attr; |
@@ -245,16 +278,11 @@ static int ps3_sys_manager_send_attr(struct ps3_vuart_port_device *dev, | |||
245 | * Tell the system manager what to do after this lpar is destroyed. | 278 | * Tell the system manager what to do after this lpar is destroyed. |
246 | */ | 279 | */ |
247 | 280 | ||
248 | static int ps3_sys_manager_send_next_op(struct ps3_vuart_port_device *dev, | 281 | static int ps3_sys_manager_send_next_op(struct ps3_system_bus_device *dev, |
249 | enum ps3_sys_manager_next_op op, | 282 | enum ps3_sys_manager_next_op op, |
250 | enum ps3_sys_manager_wake_source wake_source) | 283 | enum ps3_sys_manager_wake_source wake_source) |
251 | { | 284 | { |
252 | static const struct ps3_sys_manager_header header = { | 285 | struct ps3_sys_manager_header header; |
253 | .version = 1, | ||
254 | .size = 16, | ||
255 | .payload_size = 16, | ||
256 | .service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP, | ||
257 | }; | ||
258 | struct { | 286 | struct { |
259 | u8 version; | 287 | u8 version; |
260 | u8 type; | 288 | u8 type; |
@@ -268,6 +296,12 @@ static int ps3_sys_manager_send_next_op(struct ps3_vuart_port_device *dev, | |||
268 | 296 | ||
269 | dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op); | 297 | dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op); |
270 | 298 | ||
299 | memset(&header, 0, sizeof(header)); | ||
300 | header.version = 1; | ||
301 | header.size = 16; | ||
302 | header.payload_size = 16; | ||
303 | header.service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP; | ||
304 | |||
271 | memset(&payload, 0, sizeof(payload)); | 305 | memset(&payload, 0, sizeof(payload)); |
272 | payload.version = 3; | 306 | payload.version = 3; |
273 | payload.type = op; | 307 | payload.type = op; |
@@ -286,32 +320,35 @@ static int ps3_sys_manager_send_next_op(struct ps3_vuart_port_device *dev, | |||
286 | * the command is then communicated back to the system manager with a response | 320 | * the command is then communicated back to the system manager with a response |
287 | * message. | 321 | * message. |
288 | * | 322 | * |
289 | * Currently, the only supported request it the 'shutdown self' request. | 323 | * Currently, the only supported request is the 'shutdown self' request. |
290 | */ | 324 | */ |
291 | 325 | ||
292 | static int ps3_sys_manager_send_request_shutdown(struct ps3_vuart_port_device *dev) | 326 | static int ps3_sys_manager_send_request_shutdown( |
327 | struct ps3_system_bus_device *dev) | ||
293 | { | 328 | { |
294 | static const struct ps3_sys_manager_header header = { | 329 | struct ps3_sys_manager_header header; |
295 | .version = 1, | ||
296 | .size = 16, | ||
297 | .payload_size = 16, | ||
298 | .service_id = PS3_SM_SERVICE_ID_REQUEST, | ||
299 | }; | ||
300 | struct { | 330 | struct { |
301 | u8 version; | 331 | u8 version; |
302 | u8 type; | 332 | u8 type; |
303 | u8 gos_id; | 333 | u8 gos_id; |
304 | u8 reserved_1[13]; | 334 | u8 reserved_1[13]; |
305 | } static const payload = { | 335 | } payload; |
306 | .version = 1, | ||
307 | .type = 1, /* shutdown */ | ||
308 | .gos_id = 0, /* self */ | ||
309 | }; | ||
310 | 336 | ||
311 | BUILD_BUG_ON(sizeof(payload) != 16); | 337 | BUILD_BUG_ON(sizeof(payload) != 16); |
312 | 338 | ||
313 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 339 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
314 | 340 | ||
341 | memset(&header, 0, sizeof(header)); | ||
342 | header.version = 1; | ||
343 | header.size = 16; | ||
344 | header.payload_size = 16; | ||
345 | header.service_id = PS3_SM_SERVICE_ID_REQUEST; | ||
346 | |||
347 | memset(&payload, 0, sizeof(payload)); | ||
348 | payload.version = 1; | ||
349 | payload.type = 1; /* shutdown */ | ||
350 | payload.gos_id = 0; /* self */ | ||
351 | |||
315 | return ps3_sys_manager_write(dev, &header, &payload); | 352 | return ps3_sys_manager_write(dev, &header, &payload); |
316 | } | 353 | } |
317 | 354 | ||
@@ -323,15 +360,10 @@ static int ps3_sys_manager_send_request_shutdown(struct ps3_vuart_port_device *d | |||
323 | * failure of a command sent by the system manager. | 360 | * failure of a command sent by the system manager. |
324 | */ | 361 | */ |
325 | 362 | ||
326 | static int ps3_sys_manager_send_response(struct ps3_vuart_port_device *dev, | 363 | static int ps3_sys_manager_send_response(struct ps3_system_bus_device *dev, |
327 | u64 status) | 364 | u64 status) |
328 | { | 365 | { |
329 | static const struct ps3_sys_manager_header header = { | 366 | struct ps3_sys_manager_header header; |
330 | .version = 1, | ||
331 | .size = 16, | ||
332 | .payload_size = 16, | ||
333 | .service_id = PS3_SM_SERVICE_ID_RESPONSE, | ||
334 | }; | ||
335 | struct { | 367 | struct { |
336 | u8 version; | 368 | u8 version; |
337 | u8 reserved_1[3]; | 369 | u8 reserved_1[3]; |
@@ -344,6 +376,12 @@ static int ps3_sys_manager_send_response(struct ps3_vuart_port_device *dev, | |||
344 | dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__, | 376 | dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__, |
345 | (status ? "nak" : "ack")); | 377 | (status ? "nak" : "ack")); |
346 | 378 | ||
379 | memset(&header, 0, sizeof(header)); | ||
380 | header.version = 1; | ||
381 | header.size = 16; | ||
382 | header.payload_size = 16; | ||
383 | header.service_id = PS3_SM_SERVICE_ID_RESPONSE; | ||
384 | |||
347 | memset(&payload, 0, sizeof(payload)); | 385 | memset(&payload, 0, sizeof(payload)); |
348 | payload.version = 1; | 386 | payload.version = 1; |
349 | payload.status = status; | 387 | payload.status = status; |
@@ -356,7 +394,7 @@ static int ps3_sys_manager_send_response(struct ps3_vuart_port_device *dev, | |||
356 | * | 394 | * |
357 | */ | 395 | */ |
358 | 396 | ||
359 | static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev) | 397 | static int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev) |
360 | { | 398 | { |
361 | int result; | 399 | int result; |
362 | struct { | 400 | struct { |
@@ -370,7 +408,7 @@ static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev) | |||
370 | BUILD_BUG_ON(sizeof(event) != 16); | 408 | BUILD_BUG_ON(sizeof(event) != 16); |
371 | 409 | ||
372 | result = ps3_vuart_read(dev, &event, sizeof(event)); | 410 | result = ps3_vuart_read(dev, &event, sizeof(event)); |
373 | BUG_ON(result); | 411 | BUG_ON(result && "need to retry here"); |
374 | 412 | ||
375 | if (event.version != 1) { | 413 | if (event.version != 1) { |
376 | dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n", | 414 | dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n", |
@@ -382,11 +420,34 @@ static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev) | |||
382 | case PS3_SM_EVENT_POWER_PRESSED: | 420 | case PS3_SM_EVENT_POWER_PRESSED: |
383 | dev_dbg(&dev->core, "%s:%d: POWER_PRESSED\n", | 421 | dev_dbg(&dev->core, "%s:%d: POWER_PRESSED\n", |
384 | __func__, __LINE__); | 422 | __func__, __LINE__); |
423 | ps3_sm_force_power_off = 1; | ||
424 | /* | ||
425 | * A memory barrier is use here to sync memory since | ||
426 | * ps3_sys_manager_final_restart() could be called on | ||
427 | * another cpu. | ||
428 | */ | ||
429 | wmb(); | ||
430 | kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ | ||
385 | break; | 431 | break; |
386 | case PS3_SM_EVENT_POWER_RELEASED: | 432 | case PS3_SM_EVENT_POWER_RELEASED: |
387 | dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n", | 433 | dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n", |
388 | __func__, __LINE__, event.value); | 434 | __func__, __LINE__, event.value); |
389 | kill_cad_pid(SIGINT, 1); | 435 | break; |
436 | case PS3_SM_EVENT_RESET_PRESSED: | ||
437 | dev_dbg(&dev->core, "%s:%d: RESET_PRESSED\n", | ||
438 | __func__, __LINE__); | ||
439 | ps3_sm_force_power_off = 0; | ||
440 | /* | ||
441 | * A memory barrier is use here to sync memory since | ||
442 | * ps3_sys_manager_final_restart() could be called on | ||
443 | * another cpu. | ||
444 | */ | ||
445 | wmb(); | ||
446 | kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */ | ||
447 | break; | ||
448 | case PS3_SM_EVENT_RESET_RELEASED: | ||
449 | dev_dbg(&dev->core, "%s:%d: RESET_RELEASED (%u ms)\n", | ||
450 | __func__, __LINE__, event.value); | ||
390 | break; | 451 | break; |
391 | case PS3_SM_EVENT_THERMAL_ALERT: | 452 | case PS3_SM_EVENT_THERMAL_ALERT: |
392 | dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n", | 453 | dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n", |
@@ -411,7 +472,7 @@ static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev) | |||
411 | * The system manager sends this in reply to a 'request' message from the guest. | 472 | * The system manager sends this in reply to a 'request' message from the guest. |
412 | */ | 473 | */ |
413 | 474 | ||
414 | static int ps3_sys_manager_handle_cmd(struct ps3_vuart_port_device *dev) | 475 | static int ps3_sys_manager_handle_cmd(struct ps3_system_bus_device *dev) |
415 | { | 476 | { |
416 | int result; | 477 | int result; |
417 | struct { | 478 | struct { |
@@ -425,6 +486,7 @@ static int ps3_sys_manager_handle_cmd(struct ps3_vuart_port_device *dev) | |||
425 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 486 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
426 | 487 | ||
427 | result = ps3_vuart_read(dev, &cmd, sizeof(cmd)); | 488 | result = ps3_vuart_read(dev, &cmd, sizeof(cmd)); |
489 | BUG_ON(result && "need to retry here"); | ||
428 | 490 | ||
429 | if(result) | 491 | if(result) |
430 | return result; | 492 | return result; |
@@ -448,9 +510,10 @@ static int ps3_sys_manager_handle_cmd(struct ps3_vuart_port_device *dev) | |||
448 | /** | 510 | /** |
449 | * ps3_sys_manager_handle_msg - First stage msg handler. | 511 | * ps3_sys_manager_handle_msg - First stage msg handler. |
450 | * | 512 | * |
513 | * Can be called directly to manually poll vuart and pump message handler. | ||
451 | */ | 514 | */ |
452 | 515 | ||
453 | static int ps3_sys_manager_handle_msg(struct ps3_vuart_port_device *dev) | 516 | static int ps3_sys_manager_handle_msg(struct ps3_system_bus_device *dev) |
454 | { | 517 | { |
455 | int result; | 518 | int result; |
456 | struct ps3_sys_manager_header header; | 519 | struct ps3_sys_manager_header header; |
@@ -464,12 +527,17 @@ static int ps3_sys_manager_handle_msg(struct ps3_vuart_port_device *dev) | |||
464 | if (header.version != 1) { | 527 | if (header.version != 1) { |
465 | dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n", | 528 | dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n", |
466 | __func__, __LINE__, header.version); | 529 | __func__, __LINE__, header.version); |
530 | dump_sm_header(&header); | ||
467 | goto fail_header; | 531 | goto fail_header; |
468 | } | 532 | } |
469 | 533 | ||
470 | BUILD_BUG_ON(sizeof(header) != 16); | 534 | BUILD_BUG_ON(sizeof(header) != 16); |
471 | BUG_ON(header.size != 16); | 535 | |
472 | BUG_ON(header.payload_size != 16); | 536 | if (header.size != 16 || (header.payload_size != 8 |
537 | && header.payload_size != 16)) { | ||
538 | dump_sm_header(&header); | ||
539 | BUG(); | ||
540 | } | ||
473 | 541 | ||
474 | switch (header.service_id) { | 542 | switch (header.service_id) { |
475 | case PS3_SM_SERVICE_ID_EXTERN_EVENT: | 543 | case PS3_SM_SERVICE_ID_EXTERN_EVENT: |
@@ -478,6 +546,11 @@ static int ps3_sys_manager_handle_msg(struct ps3_vuart_port_device *dev) | |||
478 | case PS3_SM_SERVICE_ID_COMMAND: | 546 | case PS3_SM_SERVICE_ID_COMMAND: |
479 | dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__); | 547 | dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__); |
480 | return ps3_sys_manager_handle_cmd(dev); | 548 | return ps3_sys_manager_handle_cmd(dev); |
549 | case PS3_SM_SERVICE_ID_REQUEST_ERROR: | ||
550 | dev_dbg(&dev->core, "%s:%d: REQUEST_ERROR\n", __func__, | ||
551 | __LINE__); | ||
552 | dump_sm_header(&header); | ||
553 | break; | ||
481 | default: | 554 | default: |
482 | dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n", | 555 | dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n", |
483 | __func__, __LINE__, header.service_id); | 556 | __func__, __LINE__, header.service_id); |
@@ -494,45 +567,25 @@ fail_id: | |||
494 | } | 567 | } |
495 | 568 | ||
496 | /** | 569 | /** |
497 | * ps3_sys_manager_work - Asyncronous read handler. | 570 | * ps3_sys_manager_final_power_off - The final platform machine_power_off routine. |
498 | * | ||
499 | * Signaled when a complete message arrives at the vuart port. | ||
500 | */ | ||
501 | |||
502 | static void ps3_sys_manager_work(struct work_struct *work) | ||
503 | { | ||
504 | struct ps3_vuart_port_device *dev = ps3_vuart_work_to_port_device(work); | ||
505 | |||
506 | ps3_sys_manager_handle_msg(dev); | ||
507 | ps3_vuart_read_async(dev, ps3_sys_manager_work, PS3_SM_RX_MSG_LEN); | ||
508 | } | ||
509 | |||
510 | struct { | ||
511 | struct ps3_vuart_port_device *dev; | ||
512 | } static drv_priv; | ||
513 | |||
514 | /** | ||
515 | * ps3_sys_manager_restart - The final platform machine_restart routine. | ||
516 | * | 571 | * |
517 | * This routine never returns. The routine disables asyncronous vuart reads | 572 | * This routine never returns. The routine disables asynchronous vuart reads |
518 | * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge | 573 | * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge |
519 | * the shutdown command sent from the system manager. Soon after the | 574 | * the shutdown command sent from the system manager. Soon after the |
520 | * acknowledgement is sent the lpar is destroyed by the HV. This routine | 575 | * acknowledgement is sent the lpar is destroyed by the HV. This routine |
521 | * should only be called from ps3_restart(). | 576 | * should only be called from ps3_power_off() through |
577 | * ps3_sys_manager_ops.power_off. | ||
522 | */ | 578 | */ |
523 | 579 | ||
524 | void ps3_sys_manager_restart(void) | 580 | static void ps3_sys_manager_final_power_off(struct ps3_system_bus_device *dev) |
525 | { | 581 | { |
526 | struct ps3_vuart_port_device *dev = drv_priv.dev; | 582 | BUG_ON(!dev); |
527 | |||
528 | BUG_ON(!drv_priv.dev); | ||
529 | 583 | ||
530 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 584 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
531 | 585 | ||
532 | ps3_vuart_cancel_async(dev); | 586 | ps3_vuart_cancel_async(dev); |
533 | 587 | ||
534 | ps3_sys_manager_send_attr(dev, 0); | 588 | ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN, |
535 | ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_LPAR_REBOOT, | ||
536 | PS3_SM_WAKE_DEFAULT); | 589 | PS3_SM_WAKE_DEFAULT); |
537 | ps3_sys_manager_send_request_shutdown(dev); | 590 | ps3_sys_manager_send_request_shutdown(dev); |
538 | 591 | ||
@@ -543,26 +596,33 @@ void ps3_sys_manager_restart(void) | |||
543 | } | 596 | } |
544 | 597 | ||
545 | /** | 598 | /** |
546 | * ps3_sys_manager_power_off - The final platform machine_power_off routine. | 599 | * ps3_sys_manager_final_restart - The final platform machine_restart routine. |
547 | * | 600 | * |
548 | * This routine never returns. The routine disables asyncronous vuart reads | 601 | * This routine never returns. The routine disables asynchronous vuart reads |
549 | * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge | 602 | * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge |
550 | * the shutdown command sent from the system manager. Soon after the | 603 | * the shutdown command sent from the system manager. Soon after the |
551 | * acknowledgement is sent the lpar is destroyed by the HV. This routine | 604 | * acknowledgement is sent the lpar is destroyed by the HV. This routine |
552 | * should only be called from ps3_power_off(). | 605 | * should only be called from ps3_restart() through ps3_sys_manager_ops.restart. |
553 | */ | 606 | */ |
554 | 607 | ||
555 | void ps3_sys_manager_power_off(void) | 608 | static void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev) |
556 | { | 609 | { |
557 | struct ps3_vuart_port_device *dev = drv_priv.dev; | 610 | BUG_ON(!dev); |
558 | |||
559 | BUG_ON(!drv_priv.dev); | ||
560 | 611 | ||
561 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 612 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
562 | 613 | ||
614 | /* Check if we got here via a power button event. */ | ||
615 | |||
616 | if (ps3_sm_force_power_off) { | ||
617 | dev_dbg(&dev->core, "%s:%d: forcing poweroff\n", | ||
618 | __func__, __LINE__); | ||
619 | ps3_sys_manager_final_power_off(dev); | ||
620 | } | ||
621 | |||
563 | ps3_vuart_cancel_async(dev); | 622 | ps3_vuart_cancel_async(dev); |
564 | 623 | ||
565 | ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN, | 624 | ps3_sys_manager_send_attr(dev, 0); |
625 | ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_LPAR_REBOOT, | ||
566 | PS3_SM_WAKE_DEFAULT); | 626 | PS3_SM_WAKE_DEFAULT); |
567 | ps3_sys_manager_send_request_shutdown(dev); | 627 | ps3_sys_manager_send_request_shutdown(dev); |
568 | 628 | ||
@@ -572,31 +632,60 @@ void ps3_sys_manager_power_off(void) | |||
572 | ps3_sys_manager_handle_msg(dev); | 632 | ps3_sys_manager_handle_msg(dev); |
573 | } | 633 | } |
574 | 634 | ||
575 | static int ps3_sys_manager_probe(struct ps3_vuart_port_device *dev) | 635 | /** |
636 | * ps3_sys_manager_work - Asynchronous read handler. | ||
637 | * | ||
638 | * Signaled when PS3_SM_RX_MSG_LEN_MIN bytes arrive at the vuart port. | ||
639 | */ | ||
640 | |||
641 | static void ps3_sys_manager_work(struct ps3_system_bus_device *dev) | ||
642 | { | ||
643 | ps3_sys_manager_handle_msg(dev); | ||
644 | ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); | ||
645 | } | ||
646 | |||
647 | static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev) | ||
576 | { | 648 | { |
577 | int result; | 649 | int result; |
650 | struct ps3_sys_manager_ops ops; | ||
578 | 651 | ||
579 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 652 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
580 | 653 | ||
581 | BUG_ON(drv_priv.dev); | 654 | ops.power_off = ps3_sys_manager_final_power_off; |
582 | drv_priv.dev = dev; | 655 | ops.restart = ps3_sys_manager_final_restart; |
656 | ops.dev = dev; | ||
657 | |||
658 | /* ps3_sys_manager_register_ops copies ops. */ | ||
659 | |||
660 | ps3_sys_manager_register_ops(&ops); | ||
583 | 661 | ||
584 | result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL); | 662 | result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL); |
585 | BUG_ON(result); | 663 | BUG_ON(result); |
586 | 664 | ||
587 | result = ps3_vuart_read_async(dev, ps3_sys_manager_work, | 665 | result = ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); |
588 | PS3_SM_RX_MSG_LEN); | ||
589 | BUG_ON(result); | 666 | BUG_ON(result); |
590 | 667 | ||
591 | return result; | 668 | return result; |
592 | } | 669 | } |
593 | 670 | ||
671 | static int ps3_sys_manager_remove(struct ps3_system_bus_device *dev) | ||
672 | { | ||
673 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | ||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | static void ps3_sys_manager_shutdown(struct ps3_system_bus_device *dev) | ||
678 | { | ||
679 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | ||
680 | } | ||
681 | |||
594 | static struct ps3_vuart_port_driver ps3_sys_manager = { | 682 | static struct ps3_vuart_port_driver ps3_sys_manager = { |
595 | .match_id = PS3_MATCH_ID_SYSTEM_MANAGER, | 683 | .core.match_id = PS3_MATCH_ID_SYSTEM_MANAGER, |
596 | .core = { | 684 | .core.core.name = "ps3_sys_manager", |
597 | .name = "ps3_sys_manager", | ||
598 | }, | ||
599 | .probe = ps3_sys_manager_probe, | 685 | .probe = ps3_sys_manager_probe, |
686 | .remove = ps3_sys_manager_remove, | ||
687 | .shutdown = ps3_sys_manager_shutdown, | ||
688 | .work = ps3_sys_manager_work, | ||
600 | }; | 689 | }; |
601 | 690 | ||
602 | static int __init ps3_sys_manager_init(void) | 691 | static int __init ps3_sys_manager_init(void) |
@@ -608,3 +697,6 @@ static int __init ps3_sys_manager_init(void) | |||
608 | } | 697 | } |
609 | 698 | ||
610 | module_init(ps3_sys_manager_init); | 699 | module_init(ps3_sys_manager_init); |
700 | /* Module remove not supported. */ | ||
701 | |||
702 | MODULE_ALIAS(PS3_MODULE_ALIAS_SYSTEM_MANAGER); | ||
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c index ec2d36a1bc67..bea25a1391ee 100644 --- a/drivers/ps3/vuart.c +++ b/drivers/ps3/vuart.c | |||
@@ -71,6 +71,34 @@ enum vuart_interrupt_mask { | |||
71 | }; | 71 | }; |
72 | 72 | ||
73 | /** | 73 | /** |
74 | * struct ps3_vuart_port_priv - private vuart device data. | ||
75 | */ | ||
76 | |||
77 | struct ps3_vuart_port_priv { | ||
78 | u64 interrupt_mask; | ||
79 | |||
80 | struct { | ||
81 | spinlock_t lock; | ||
82 | struct list_head head; | ||
83 | } tx_list; | ||
84 | struct { | ||
85 | struct ps3_vuart_work work; | ||
86 | unsigned long bytes_held; | ||
87 | spinlock_t lock; | ||
88 | struct list_head head; | ||
89 | } rx_list; | ||
90 | struct ps3_vuart_stats stats; | ||
91 | }; | ||
92 | |||
93 | static struct ps3_vuart_port_priv *to_port_priv( | ||
94 | struct ps3_system_bus_device *dev) | ||
95 | { | ||
96 | BUG_ON(!dev); | ||
97 | BUG_ON(!dev->driver_priv); | ||
98 | return (struct ps3_vuart_port_priv *)dev->driver_priv; | ||
99 | } | ||
100 | |||
101 | /** | ||
74 | * struct ports_bmp - bitmap indicating ports needing service. | 102 | * struct ports_bmp - bitmap indicating ports needing service. |
75 | * | 103 | * |
76 | * A 256 bit read only bitmap indicating ports needing service. Do not write | 104 | * A 256 bit read only bitmap indicating ports needing service. Do not write |
@@ -83,31 +111,14 @@ struct ports_bmp { | |||
83 | } __attribute__ ((aligned (32))); | 111 | } __attribute__ ((aligned (32))); |
84 | 112 | ||
85 | #define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__) | 113 | #define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__) |
86 | static void __attribute__ ((unused)) _dump_ports_bmp( | 114 | static void __maybe_unused _dump_ports_bmp( |
87 | const struct ports_bmp* bmp, const char* func, int line) | 115 | const struct ports_bmp* bmp, const char* func, int line) |
88 | { | 116 | { |
89 | pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status); | 117 | pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status); |
90 | } | 118 | } |
91 | 119 | ||
92 | static int ps3_vuart_match_id_to_port(enum ps3_match_id match_id, | ||
93 | unsigned int *port_number) | ||
94 | { | ||
95 | switch(match_id) { | ||
96 | case PS3_MATCH_ID_AV_SETTINGS: | ||
97 | *port_number = 0; | ||
98 | return 0; | ||
99 | case PS3_MATCH_ID_SYSTEM_MANAGER: | ||
100 | *port_number = 2; | ||
101 | return 0; | ||
102 | default: | ||
103 | WARN_ON(1); | ||
104 | *port_number = UINT_MAX; | ||
105 | return -EINVAL; | ||
106 | }; | ||
107 | } | ||
108 | |||
109 | #define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__) | 120 | #define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__) |
110 | static void __attribute__ ((unused)) _dump_port_params(unsigned int port_number, | 121 | static void __maybe_unused _dump_port_params(unsigned int port_number, |
111 | const char* func, int line) | 122 | const char* func, int line) |
112 | { | 123 | { |
113 | #if defined(DEBUG) | 124 | #if defined(DEBUG) |
@@ -144,14 +155,14 @@ struct vuart_triggers { | |||
144 | unsigned long tx; | 155 | unsigned long tx; |
145 | }; | 156 | }; |
146 | 157 | ||
147 | int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, | 158 | int ps3_vuart_get_triggers(struct ps3_system_bus_device *dev, |
148 | struct vuart_triggers *trig) | 159 | struct vuart_triggers *trig) |
149 | { | 160 | { |
150 | int result; | 161 | int result; |
151 | unsigned long size; | 162 | unsigned long size; |
152 | unsigned long val; | 163 | unsigned long val; |
153 | 164 | ||
154 | result = lv1_get_virtual_uart_param(dev->priv->port_number, | 165 | result = lv1_get_virtual_uart_param(dev->port_number, |
155 | PARAM_TX_TRIGGER, &trig->tx); | 166 | PARAM_TX_TRIGGER, &trig->tx); |
156 | 167 | ||
157 | if (result) { | 168 | if (result) { |
@@ -160,7 +171,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, | |||
160 | return result; | 171 | return result; |
161 | } | 172 | } |
162 | 173 | ||
163 | result = lv1_get_virtual_uart_param(dev->priv->port_number, | 174 | result = lv1_get_virtual_uart_param(dev->port_number, |
164 | PARAM_RX_BUF_SIZE, &size); | 175 | PARAM_RX_BUF_SIZE, &size); |
165 | 176 | ||
166 | if (result) { | 177 | if (result) { |
@@ -169,7 +180,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, | |||
169 | return result; | 180 | return result; |
170 | } | 181 | } |
171 | 182 | ||
172 | result = lv1_get_virtual_uart_param(dev->priv->port_number, | 183 | result = lv1_get_virtual_uart_param(dev->port_number, |
173 | PARAM_RX_TRIGGER, &val); | 184 | PARAM_RX_TRIGGER, &val); |
174 | 185 | ||
175 | if (result) { | 186 | if (result) { |
@@ -186,13 +197,13 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev, | |||
186 | return result; | 197 | return result; |
187 | } | 198 | } |
188 | 199 | ||
189 | int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, | 200 | int ps3_vuart_set_triggers(struct ps3_system_bus_device *dev, unsigned int tx, |
190 | unsigned int rx) | 201 | unsigned int rx) |
191 | { | 202 | { |
192 | int result; | 203 | int result; |
193 | unsigned long size; | 204 | unsigned long size; |
194 | 205 | ||
195 | result = lv1_set_virtual_uart_param(dev->priv->port_number, | 206 | result = lv1_set_virtual_uart_param(dev->port_number, |
196 | PARAM_TX_TRIGGER, tx); | 207 | PARAM_TX_TRIGGER, tx); |
197 | 208 | ||
198 | if (result) { | 209 | if (result) { |
@@ -201,7 +212,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, | |||
201 | return result; | 212 | return result; |
202 | } | 213 | } |
203 | 214 | ||
204 | result = lv1_get_virtual_uart_param(dev->priv->port_number, | 215 | result = lv1_get_virtual_uart_param(dev->port_number, |
205 | PARAM_RX_BUF_SIZE, &size); | 216 | PARAM_RX_BUF_SIZE, &size); |
206 | 217 | ||
207 | if (result) { | 218 | if (result) { |
@@ -210,7 +221,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, | |||
210 | return result; | 221 | return result; |
211 | } | 222 | } |
212 | 223 | ||
213 | result = lv1_set_virtual_uart_param(dev->priv->port_number, | 224 | result = lv1_set_virtual_uart_param(dev->port_number, |
214 | PARAM_RX_TRIGGER, size - rx); | 225 | PARAM_RX_TRIGGER, size - rx); |
215 | 226 | ||
216 | if (result) { | 227 | if (result) { |
@@ -225,10 +236,12 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx, | |||
225 | return result; | 236 | return result; |
226 | } | 237 | } |
227 | 238 | ||
228 | static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev, | 239 | static int ps3_vuart_get_rx_bytes_waiting(struct ps3_system_bus_device *dev, |
229 | u64 *bytes_waiting) | 240 | u64 *bytes_waiting) |
230 | { | 241 | { |
231 | int result = lv1_get_virtual_uart_param(dev->priv->port_number, | 242 | int result; |
243 | |||
244 | result = lv1_get_virtual_uart_param(dev->port_number, | ||
232 | PARAM_RX_BYTES, bytes_waiting); | 245 | PARAM_RX_BYTES, bytes_waiting); |
233 | 246 | ||
234 | if (result) | 247 | if (result) |
@@ -240,17 +253,24 @@ static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev, | |||
240 | return result; | 253 | return result; |
241 | } | 254 | } |
242 | 255 | ||
243 | static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev, | 256 | /** |
257 | * ps3_vuart_set_interrupt_mask - Enable/disable the port interrupt sources. | ||
258 | * @dev: The struct ps3_system_bus_device instance. | ||
259 | * @bmp: Logical OR of enum vuart_interrupt_mask values. A zero bit disables. | ||
260 | */ | ||
261 | |||
262 | static int ps3_vuart_set_interrupt_mask(struct ps3_system_bus_device *dev, | ||
244 | unsigned long mask) | 263 | unsigned long mask) |
245 | { | 264 | { |
246 | int result; | 265 | int result; |
266 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
247 | 267 | ||
248 | dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask); | 268 | dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask); |
249 | 269 | ||
250 | dev->priv->interrupt_mask = mask; | 270 | priv->interrupt_mask = mask; |
251 | 271 | ||
252 | result = lv1_set_virtual_uart_param(dev->priv->port_number, | 272 | result = lv1_set_virtual_uart_param(dev->port_number, |
253 | PARAM_INTERRUPT_MASK, dev->priv->interrupt_mask); | 273 | PARAM_INTERRUPT_MASK, priv->interrupt_mask); |
254 | 274 | ||
255 | if (result) | 275 | if (result) |
256 | dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n", | 276 | dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n", |
@@ -259,79 +279,96 @@ static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev, | |||
259 | return result; | 279 | return result; |
260 | } | 280 | } |
261 | 281 | ||
262 | static int ps3_vuart_get_interrupt_status(struct ps3_vuart_port_device *dev, | 282 | static int ps3_vuart_get_interrupt_status(struct ps3_system_bus_device *dev, |
263 | unsigned long *status) | 283 | unsigned long *status) |
264 | { | 284 | { |
285 | int result; | ||
286 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
265 | u64 tmp; | 287 | u64 tmp; |
266 | int result = lv1_get_virtual_uart_param(dev->priv->port_number, | 288 | |
289 | result = lv1_get_virtual_uart_param(dev->port_number, | ||
267 | PARAM_INTERRUPT_STATUS, &tmp); | 290 | PARAM_INTERRUPT_STATUS, &tmp); |
268 | 291 | ||
269 | if (result) | 292 | if (result) |
270 | dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n", | 293 | dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n", |
271 | __func__, __LINE__, ps3_result(result)); | 294 | __func__, __LINE__, ps3_result(result)); |
272 | 295 | ||
273 | *status = tmp & dev->priv->interrupt_mask; | 296 | *status = tmp & priv->interrupt_mask; |
274 | 297 | ||
275 | dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n", | 298 | dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n", |
276 | __func__, __LINE__, dev->priv->interrupt_mask, tmp, *status); | 299 | __func__, __LINE__, priv->interrupt_mask, tmp, *status); |
277 | 300 | ||
278 | return result; | 301 | return result; |
279 | } | 302 | } |
280 | 303 | ||
281 | int ps3_vuart_enable_interrupt_tx(struct ps3_vuart_port_device *dev) | 304 | int ps3_vuart_enable_interrupt_tx(struct ps3_system_bus_device *dev) |
282 | { | 305 | { |
283 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_TX) ? 0 | 306 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
284 | : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | 307 | |
308 | return (priv->interrupt_mask & INTERRUPT_MASK_TX) ? 0 | ||
309 | : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask | ||
285 | | INTERRUPT_MASK_TX); | 310 | | INTERRUPT_MASK_TX); |
286 | } | 311 | } |
287 | 312 | ||
288 | int ps3_vuart_enable_interrupt_rx(struct ps3_vuart_port_device *dev) | 313 | int ps3_vuart_enable_interrupt_rx(struct ps3_system_bus_device *dev) |
289 | { | 314 | { |
290 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_RX) ? 0 | 315 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
291 | : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | 316 | |
317 | return (priv->interrupt_mask & INTERRUPT_MASK_RX) ? 0 | ||
318 | : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask | ||
292 | | INTERRUPT_MASK_RX); | 319 | | INTERRUPT_MASK_RX); |
293 | } | 320 | } |
294 | 321 | ||
295 | int ps3_vuart_enable_interrupt_disconnect(struct ps3_vuart_port_device *dev) | 322 | int ps3_vuart_enable_interrupt_disconnect(struct ps3_system_bus_device *dev) |
296 | { | 323 | { |
297 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0 | 324 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
298 | : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | 325 | |
326 | return (priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0 | ||
327 | : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask | ||
299 | | INTERRUPT_MASK_DISCONNECT); | 328 | | INTERRUPT_MASK_DISCONNECT); |
300 | } | 329 | } |
301 | 330 | ||
302 | int ps3_vuart_disable_interrupt_tx(struct ps3_vuart_port_device *dev) | 331 | int ps3_vuart_disable_interrupt_tx(struct ps3_system_bus_device *dev) |
303 | { | 332 | { |
304 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_TX) | 333 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
305 | ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | 334 | |
335 | return (priv->interrupt_mask & INTERRUPT_MASK_TX) | ||
336 | ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask | ||
306 | & ~INTERRUPT_MASK_TX) : 0; | 337 | & ~INTERRUPT_MASK_TX) : 0; |
307 | } | 338 | } |
308 | 339 | ||
309 | int ps3_vuart_disable_interrupt_rx(struct ps3_vuart_port_device *dev) | 340 | int ps3_vuart_disable_interrupt_rx(struct ps3_system_bus_device *dev) |
310 | { | 341 | { |
311 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_RX) | 342 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
312 | ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | 343 | |
344 | return (priv->interrupt_mask & INTERRUPT_MASK_RX) | ||
345 | ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask | ||
313 | & ~INTERRUPT_MASK_RX) : 0; | 346 | & ~INTERRUPT_MASK_RX) : 0; |
314 | } | 347 | } |
315 | 348 | ||
316 | int ps3_vuart_disable_interrupt_disconnect(struct ps3_vuart_port_device *dev) | 349 | int ps3_vuart_disable_interrupt_disconnect(struct ps3_system_bus_device *dev) |
317 | { | 350 | { |
318 | return (dev->priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) | 351 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
319 | ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask | 352 | |
353 | return (priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) | ||
354 | ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask | ||
320 | & ~INTERRUPT_MASK_DISCONNECT) : 0; | 355 | & ~INTERRUPT_MASK_DISCONNECT) : 0; |
321 | } | 356 | } |
322 | 357 | ||
323 | /** | 358 | /** |
324 | * ps3_vuart_raw_write - Low level write helper. | 359 | * ps3_vuart_raw_write - Low level write helper. |
360 | * @dev: The struct ps3_system_bus_device instance. | ||
325 | * | 361 | * |
326 | * Do not call ps3_vuart_raw_write directly, use ps3_vuart_write. | 362 | * Do not call ps3_vuart_raw_write directly, use ps3_vuart_write. |
327 | */ | 363 | */ |
328 | 364 | ||
329 | static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev, | 365 | static int ps3_vuart_raw_write(struct ps3_system_bus_device *dev, |
330 | const void* buf, unsigned int bytes, unsigned long *bytes_written) | 366 | const void* buf, unsigned int bytes, unsigned long *bytes_written) |
331 | { | 367 | { |
332 | int result; | 368 | int result; |
369 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
333 | 370 | ||
334 | result = lv1_write_virtual_uart(dev->priv->port_number, | 371 | result = lv1_write_virtual_uart(dev->port_number, |
335 | ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written); | 372 | ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written); |
336 | 373 | ||
337 | if (result) { | 374 | if (result) { |
@@ -340,28 +377,30 @@ static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev, | |||
340 | return result; | 377 | return result; |
341 | } | 378 | } |
342 | 379 | ||
343 | dev->priv->stats.bytes_written += *bytes_written; | 380 | priv->stats.bytes_written += *bytes_written; |
344 | 381 | ||
345 | dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__, __LINE__, | 382 | dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__, __LINE__, |
346 | *bytes_written, bytes, dev->priv->stats.bytes_written); | 383 | *bytes_written, bytes, priv->stats.bytes_written); |
347 | 384 | ||
348 | return result; | 385 | return result; |
349 | } | 386 | } |
350 | 387 | ||
351 | /** | 388 | /** |
352 | * ps3_vuart_raw_read - Low level read helper. | 389 | * ps3_vuart_raw_read - Low level read helper. |
390 | * @dev: The struct ps3_system_bus_device instance. | ||
353 | * | 391 | * |
354 | * Do not call ps3_vuart_raw_read directly, use ps3_vuart_read. | 392 | * Do not call ps3_vuart_raw_read directly, use ps3_vuart_read. |
355 | */ | 393 | */ |
356 | 394 | ||
357 | static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf, | 395 | static int ps3_vuart_raw_read(struct ps3_system_bus_device *dev, void *buf, |
358 | unsigned int bytes, unsigned long *bytes_read) | 396 | unsigned int bytes, unsigned long *bytes_read) |
359 | { | 397 | { |
360 | int result; | 398 | int result; |
399 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
361 | 400 | ||
362 | dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes); | 401 | dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes); |
363 | 402 | ||
364 | result = lv1_read_virtual_uart(dev->priv->port_number, | 403 | result = lv1_read_virtual_uart(dev->port_number, |
365 | ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read); | 404 | ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read); |
366 | 405 | ||
367 | if (result) { | 406 | if (result) { |
@@ -370,25 +409,27 @@ static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf, | |||
370 | return result; | 409 | return result; |
371 | } | 410 | } |
372 | 411 | ||
373 | dev->priv->stats.bytes_read += *bytes_read; | 412 | priv->stats.bytes_read += *bytes_read; |
374 | 413 | ||
375 | dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__, | 414 | dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__, |
376 | *bytes_read, bytes, dev->priv->stats.bytes_read); | 415 | *bytes_read, bytes, priv->stats.bytes_read); |
377 | 416 | ||
378 | return result; | 417 | return result; |
379 | } | 418 | } |
380 | 419 | ||
381 | /** | 420 | /** |
382 | * ps3_vuart_clear_rx_bytes - Discard bytes received. | 421 | * ps3_vuart_clear_rx_bytes - Discard bytes received. |
422 | * @dev: The struct ps3_system_bus_device instance. | ||
383 | * @bytes: Max byte count to discard, zero = all pending. | 423 | * @bytes: Max byte count to discard, zero = all pending. |
384 | * | 424 | * |
385 | * Used to clear pending rx interrupt source. Will not block. | 425 | * Used to clear pending rx interrupt source. Will not block. |
386 | */ | 426 | */ |
387 | 427 | ||
388 | void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev, | 428 | void ps3_vuart_clear_rx_bytes(struct ps3_system_bus_device *dev, |
389 | unsigned int bytes) | 429 | unsigned int bytes) |
390 | { | 430 | { |
391 | int result; | 431 | int result; |
432 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
392 | u64 bytes_waiting; | 433 | u64 bytes_waiting; |
393 | void* tmp; | 434 | void* tmp; |
394 | 435 | ||
@@ -418,8 +459,9 @@ void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev, | |||
418 | 459 | ||
419 | /* Don't include these bytes in the stats. */ | 460 | /* Don't include these bytes in the stats. */ |
420 | 461 | ||
421 | dev->priv->stats.bytes_read -= bytes_waiting; | 462 | priv->stats.bytes_read -= bytes_waiting; |
422 | } | 463 | } |
464 | EXPORT_SYMBOL_GPL(ps3_vuart_clear_rx_bytes); | ||
423 | 465 | ||
424 | /** | 466 | /** |
425 | * struct list_buffer - An element for a port device fifo buffer list. | 467 | * struct list_buffer - An element for a port device fifo buffer list. |
@@ -435,6 +477,7 @@ struct list_buffer { | |||
435 | 477 | ||
436 | /** | 478 | /** |
437 | * ps3_vuart_write - the entry point for writing data to a port | 479 | * ps3_vuart_write - the entry point for writing data to a port |
480 | * @dev: The struct ps3_system_bus_device instance. | ||
438 | * | 481 | * |
439 | * If the port is idle on entry as much of the incoming data is written to | 482 | * If the port is idle on entry as much of the incoming data is written to |
440 | * the port as the port will accept. Otherwise a list buffer is created | 483 | * the port as the port will accept. Otherwise a list buffer is created |
@@ -442,25 +485,26 @@ struct list_buffer { | |||
442 | * then enqueued for transmision via the transmit interrupt. | 485 | * then enqueued for transmision via the transmit interrupt. |
443 | */ | 486 | */ |
444 | 487 | ||
445 | int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, | 488 | int ps3_vuart_write(struct ps3_system_bus_device *dev, const void *buf, |
446 | unsigned int bytes) | 489 | unsigned int bytes) |
447 | { | 490 | { |
448 | static unsigned long dbg_number; | 491 | static unsigned long dbg_number; |
449 | int result; | 492 | int result; |
493 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
450 | unsigned long flags; | 494 | unsigned long flags; |
451 | struct list_buffer *lb; | 495 | struct list_buffer *lb; |
452 | 496 | ||
453 | dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, | 497 | dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, |
454 | bytes, bytes); | 498 | bytes, bytes); |
455 | 499 | ||
456 | spin_lock_irqsave(&dev->priv->tx_list.lock, flags); | 500 | spin_lock_irqsave(&priv->tx_list.lock, flags); |
457 | 501 | ||
458 | if (list_empty(&dev->priv->tx_list.head)) { | 502 | if (list_empty(&priv->tx_list.head)) { |
459 | unsigned long bytes_written; | 503 | unsigned long bytes_written; |
460 | 504 | ||
461 | result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written); | 505 | result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written); |
462 | 506 | ||
463 | spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); | 507 | spin_unlock_irqrestore(&priv->tx_list.lock, flags); |
464 | 508 | ||
465 | if (result) { | 509 | if (result) { |
466 | dev_dbg(&dev->core, | 510 | dev_dbg(&dev->core, |
@@ -478,7 +522,7 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, | |||
478 | bytes -= bytes_written; | 522 | bytes -= bytes_written; |
479 | buf += bytes_written; | 523 | buf += bytes_written; |
480 | } else | 524 | } else |
481 | spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); | 525 | spin_unlock_irqrestore(&priv->tx_list.lock, flags); |
482 | 526 | ||
483 | lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL); | 527 | lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL); |
484 | 528 | ||
@@ -491,29 +535,86 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, | |||
491 | lb->tail = lb->data + bytes; | 535 | lb->tail = lb->data + bytes; |
492 | lb->dbg_number = ++dbg_number; | 536 | lb->dbg_number = ++dbg_number; |
493 | 537 | ||
494 | spin_lock_irqsave(&dev->priv->tx_list.lock, flags); | 538 | spin_lock_irqsave(&priv->tx_list.lock, flags); |
495 | list_add_tail(&lb->link, &dev->priv->tx_list.head); | 539 | list_add_tail(&lb->link, &priv->tx_list.head); |
496 | ps3_vuart_enable_interrupt_tx(dev); | 540 | ps3_vuart_enable_interrupt_tx(dev); |
497 | spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); | 541 | spin_unlock_irqrestore(&priv->tx_list.lock, flags); |
498 | 542 | ||
499 | dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n", | 543 | dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n", |
500 | __func__, __LINE__, lb->dbg_number, bytes); | 544 | __func__, __LINE__, lb->dbg_number, bytes); |
501 | 545 | ||
502 | return 0; | 546 | return 0; |
503 | } | 547 | } |
548 | EXPORT_SYMBOL_GPL(ps3_vuart_write); | ||
549 | |||
550 | /** | ||
551 | * ps3_vuart_queue_rx_bytes - Queue waiting bytes into the buffer list. | ||
552 | * @dev: The struct ps3_system_bus_device instance. | ||
553 | * @bytes_queued: Number of bytes queued to the buffer list. | ||
554 | * | ||
555 | * Must be called with priv->rx_list.lock held. | ||
556 | */ | ||
557 | |||
558 | static int ps3_vuart_queue_rx_bytes(struct ps3_system_bus_device *dev, | ||
559 | u64 *bytes_queued) | ||
560 | { | ||
561 | static unsigned long dbg_number; | ||
562 | int result; | ||
563 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
564 | struct list_buffer *lb; | ||
565 | u64 bytes; | ||
566 | |||
567 | *bytes_queued = 0; | ||
568 | |||
569 | result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes); | ||
570 | BUG_ON(result); | ||
571 | |||
572 | if (result) | ||
573 | return -EIO; | ||
574 | |||
575 | if (!bytes) | ||
576 | return 0; | ||
577 | |||
578 | /* Add some extra space for recently arrived data. */ | ||
579 | |||
580 | bytes += 128; | ||
581 | |||
582 | lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_ATOMIC); | ||
583 | |||
584 | if (!lb) | ||
585 | return -ENOMEM; | ||
586 | |||
587 | ps3_vuart_raw_read(dev, lb->data, bytes, &bytes); | ||
588 | |||
589 | lb->head = lb->data; | ||
590 | lb->tail = lb->data + bytes; | ||
591 | lb->dbg_number = ++dbg_number; | ||
592 | |||
593 | list_add_tail(&lb->link, &priv->rx_list.head); | ||
594 | priv->rx_list.bytes_held += bytes; | ||
595 | |||
596 | dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n", | ||
597 | __func__, __LINE__, lb->dbg_number, bytes); | ||
598 | |||
599 | *bytes_queued = bytes; | ||
600 | |||
601 | return 0; | ||
602 | } | ||
504 | 603 | ||
505 | /** | 604 | /** |
506 | * ps3_vuart_read - the entry point for reading data from a port | 605 | * ps3_vuart_read - The entry point for reading data from a port. |
507 | * | 606 | * |
508 | * If enough bytes to satisfy the request are held in the buffer list those | 607 | * Queue data waiting at the port, and if enough bytes to satisfy the request |
509 | * bytes are dequeued and copied to the caller's buffer. Emptied list buffers | 608 | * are held in the buffer list those bytes are dequeued and copied to the |
510 | * are retiered. If the request cannot be statified by bytes held in the list | 609 | * caller's buffer. Emptied list buffers are retiered. If the request cannot |
511 | * buffers -EAGAIN is returned. | 610 | * be statified by bytes held in the list buffers -EAGAIN is returned. |
512 | */ | 611 | */ |
513 | 612 | ||
514 | int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, | 613 | int ps3_vuart_read(struct ps3_system_bus_device *dev, void *buf, |
515 | unsigned int bytes) | 614 | unsigned int bytes) |
516 | { | 615 | { |
616 | int result; | ||
617 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
517 | unsigned long flags; | 618 | unsigned long flags; |
518 | struct list_buffer *lb, *n; | 619 | struct list_buffer *lb, *n; |
519 | unsigned long bytes_read; | 620 | unsigned long bytes_read; |
@@ -521,30 +622,37 @@ int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, | |||
521 | dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, | 622 | dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, |
522 | bytes, bytes); | 623 | bytes, bytes); |
523 | 624 | ||
524 | spin_lock_irqsave(&dev->priv->rx_list.lock, flags); | 625 | spin_lock_irqsave(&priv->rx_list.lock, flags); |
525 | 626 | ||
526 | if (dev->priv->rx_list.bytes_held < bytes) { | 627 | /* Queue rx bytes here for polled reads. */ |
527 | spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); | 628 | |
528 | dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n", | 629 | while (priv->rx_list.bytes_held < bytes) { |
529 | __func__, __LINE__, | 630 | u64 tmp; |
530 | bytes - dev->priv->rx_list.bytes_held); | 631 | |
531 | return -EAGAIN; | 632 | result = ps3_vuart_queue_rx_bytes(dev, &tmp); |
633 | if (result || !tmp) { | ||
634 | dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n", | ||
635 | __func__, __LINE__, | ||
636 | bytes - priv->rx_list.bytes_held); | ||
637 | spin_unlock_irqrestore(&priv->rx_list.lock, flags); | ||
638 | return -EAGAIN; | ||
639 | } | ||
532 | } | 640 | } |
533 | 641 | ||
534 | list_for_each_entry_safe(lb, n, &dev->priv->rx_list.head, link) { | 642 | list_for_each_entry_safe(lb, n, &priv->rx_list.head, link) { |
535 | bytes_read = min((unsigned int)(lb->tail - lb->head), bytes); | 643 | bytes_read = min((unsigned int)(lb->tail - lb->head), bytes); |
536 | 644 | ||
537 | memcpy(buf, lb->head, bytes_read); | 645 | memcpy(buf, lb->head, bytes_read); |
538 | buf += bytes_read; | 646 | buf += bytes_read; |
539 | bytes -= bytes_read; | 647 | bytes -= bytes_read; |
540 | dev->priv->rx_list.bytes_held -= bytes_read; | 648 | priv->rx_list.bytes_held -= bytes_read; |
541 | 649 | ||
542 | if (bytes_read < lb->tail - lb->head) { | 650 | if (bytes_read < lb->tail - lb->head) { |
543 | lb->head += bytes_read; | 651 | lb->head += bytes_read; |
544 | dev_dbg(&dev->core, "%s:%d: buf_%lu: dequeued %lxh " | 652 | dev_dbg(&dev->core, "%s:%d: buf_%lu: dequeued %lxh " |
545 | "bytes\n", __func__, __LINE__, lb->dbg_number, | 653 | "bytes\n", __func__, __LINE__, lb->dbg_number, |
546 | bytes_read); | 654 | bytes_read); |
547 | spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); | 655 | spin_unlock_irqrestore(&priv->rx_list.lock, flags); |
548 | return 0; | 656 | return 0; |
549 | } | 657 | } |
550 | 658 | ||
@@ -556,16 +664,32 @@ int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, | |||
556 | kfree(lb); | 664 | kfree(lb); |
557 | } | 665 | } |
558 | 666 | ||
559 | spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); | 667 | spin_unlock_irqrestore(&priv->rx_list.lock, flags); |
560 | return 0; | 668 | return 0; |
561 | } | 669 | } |
670 | EXPORT_SYMBOL_GPL(ps3_vuart_read); | ||
562 | 671 | ||
563 | int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func, | 672 | /** |
564 | unsigned int bytes) | 673 | * ps3_vuart_work - Asynchronous read handler. |
674 | */ | ||
675 | |||
676 | static void ps3_vuart_work(struct work_struct *work) | ||
677 | { | ||
678 | struct ps3_system_bus_device *dev = | ||
679 | ps3_vuart_work_to_system_bus_dev(work); | ||
680 | struct ps3_vuart_port_driver *drv = | ||
681 | ps3_system_bus_dev_to_vuart_drv(dev); | ||
682 | |||
683 | BUG_ON(!drv); | ||
684 | drv->work(dev); | ||
685 | } | ||
686 | |||
687 | int ps3_vuart_read_async(struct ps3_system_bus_device *dev, unsigned int bytes) | ||
565 | { | 688 | { |
689 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
566 | unsigned long flags; | 690 | unsigned long flags; |
567 | 691 | ||
568 | if(dev->priv->work.trigger) { | 692 | if (priv->rx_list.work.trigger) { |
569 | dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n", | 693 | dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n", |
570 | __func__, __LINE__); | 694 | __func__, __LINE__); |
571 | return -EAGAIN; | 695 | return -EAGAIN; |
@@ -573,30 +697,32 @@ int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func, | |||
573 | 697 | ||
574 | BUG_ON(!bytes); | 698 | BUG_ON(!bytes); |
575 | 699 | ||
576 | PREPARE_WORK(&dev->priv->work.work, func); | 700 | PREPARE_WORK(&priv->rx_list.work.work, ps3_vuart_work); |
577 | 701 | ||
578 | spin_lock_irqsave(&dev->priv->work.lock, flags); | 702 | spin_lock_irqsave(&priv->rx_list.lock, flags); |
579 | if(dev->priv->rx_list.bytes_held >= bytes) { | 703 | if (priv->rx_list.bytes_held >= bytes) { |
580 | dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n", | 704 | dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n", |
581 | __func__, __LINE__, bytes); | 705 | __func__, __LINE__, bytes); |
582 | schedule_work(&dev->priv->work.work); | 706 | schedule_work(&priv->rx_list.work.work); |
583 | spin_unlock_irqrestore(&dev->priv->work.lock, flags); | 707 | spin_unlock_irqrestore(&priv->rx_list.lock, flags); |
584 | return 0; | 708 | return 0; |
585 | } | 709 | } |
586 | 710 | ||
587 | dev->priv->work.trigger = bytes; | 711 | priv->rx_list.work.trigger = bytes; |
588 | spin_unlock_irqrestore(&dev->priv->work.lock, flags); | 712 | spin_unlock_irqrestore(&priv->rx_list.lock, flags); |
589 | 713 | ||
590 | dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__, | 714 | dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__, |
591 | __LINE__, bytes, bytes); | 715 | __LINE__, bytes, bytes); |
592 | 716 | ||
593 | return 0; | 717 | return 0; |
594 | } | 718 | } |
719 | EXPORT_SYMBOL_GPL(ps3_vuart_read_async); | ||
595 | 720 | ||
596 | void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev) | 721 | void ps3_vuart_cancel_async(struct ps3_system_bus_device *dev) |
597 | { | 722 | { |
598 | dev->priv->work.trigger = 0; | 723 | to_port_priv(dev)->rx_list.work.trigger = 0; |
599 | } | 724 | } |
725 | EXPORT_SYMBOL_GPL(ps3_vuart_cancel_async); | ||
600 | 726 | ||
601 | /** | 727 | /** |
602 | * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler | 728 | * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler |
@@ -606,18 +732,19 @@ void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev) | |||
606 | * adjusts the final list buffer state for a partial write. | 732 | * adjusts the final list buffer state for a partial write. |
607 | */ | 733 | */ |
608 | 734 | ||
609 | static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev) | 735 | static int ps3_vuart_handle_interrupt_tx(struct ps3_system_bus_device *dev) |
610 | { | 736 | { |
611 | int result = 0; | 737 | int result = 0; |
738 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
612 | unsigned long flags; | 739 | unsigned long flags; |
613 | struct list_buffer *lb, *n; | 740 | struct list_buffer *lb, *n; |
614 | unsigned long bytes_total = 0; | 741 | unsigned long bytes_total = 0; |
615 | 742 | ||
616 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 743 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
617 | 744 | ||
618 | spin_lock_irqsave(&dev->priv->tx_list.lock, flags); | 745 | spin_lock_irqsave(&priv->tx_list.lock, flags); |
619 | 746 | ||
620 | list_for_each_entry_safe(lb, n, &dev->priv->tx_list.head, link) { | 747 | list_for_each_entry_safe(lb, n, &priv->tx_list.head, link) { |
621 | 748 | ||
622 | unsigned long bytes_written; | 749 | unsigned long bytes_written; |
623 | 750 | ||
@@ -651,7 +778,7 @@ static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev) | |||
651 | 778 | ||
652 | ps3_vuart_disable_interrupt_tx(dev); | 779 | ps3_vuart_disable_interrupt_tx(dev); |
653 | port_full: | 780 | port_full: |
654 | spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags); | 781 | spin_unlock_irqrestore(&priv->tx_list.lock, flags); |
655 | dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n", | 782 | dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n", |
656 | __func__, __LINE__, bytes_total); | 783 | __func__, __LINE__, bytes_total); |
657 | return result; | 784 | return result; |
@@ -665,60 +792,37 @@ port_full: | |||
665 | * buffer list. Buffer list data is dequeued via ps3_vuart_read. | 792 | * buffer list. Buffer list data is dequeued via ps3_vuart_read. |
666 | */ | 793 | */ |
667 | 794 | ||
668 | static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev) | 795 | static int ps3_vuart_handle_interrupt_rx(struct ps3_system_bus_device *dev) |
669 | { | 796 | { |
670 | static unsigned long dbg_number; | 797 | int result; |
671 | int result = 0; | 798 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); |
672 | unsigned long flags; | 799 | unsigned long flags; |
673 | struct list_buffer *lb; | 800 | u64 bytes; |
674 | unsigned long bytes; | ||
675 | 801 | ||
676 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 802 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
677 | 803 | ||
678 | result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes); | 804 | spin_lock_irqsave(&priv->rx_list.lock, flags); |
679 | 805 | result = ps3_vuart_queue_rx_bytes(dev, &bytes); | |
680 | if (result) | ||
681 | return -EIO; | ||
682 | |||
683 | BUG_ON(!bytes); | ||
684 | |||
685 | /* Add some extra space for recently arrived data. */ | ||
686 | |||
687 | bytes += 128; | ||
688 | |||
689 | lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_ATOMIC); | ||
690 | 806 | ||
691 | if (!lb) | 807 | if (result) { |
692 | return -ENOMEM; | 808 | spin_unlock_irqrestore(&priv->rx_list.lock, flags); |
693 | 809 | return result; | |
694 | ps3_vuart_raw_read(dev, lb->data, bytes, &bytes); | 810 | } |
695 | |||
696 | lb->head = lb->data; | ||
697 | lb->tail = lb->data + bytes; | ||
698 | lb->dbg_number = ++dbg_number; | ||
699 | |||
700 | spin_lock_irqsave(&dev->priv->rx_list.lock, flags); | ||
701 | list_add_tail(&lb->link, &dev->priv->rx_list.head); | ||
702 | dev->priv->rx_list.bytes_held += bytes; | ||
703 | spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags); | ||
704 | |||
705 | dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n", | ||
706 | __func__, __LINE__, lb->dbg_number, bytes); | ||
707 | 811 | ||
708 | spin_lock_irqsave(&dev->priv->work.lock, flags); | 812 | if (priv->rx_list.work.trigger && priv->rx_list.bytes_held |
709 | if(dev->priv->work.trigger | 813 | >= priv->rx_list.work.trigger) { |
710 | && dev->priv->rx_list.bytes_held >= dev->priv->work.trigger) { | ||
711 | dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n", | 814 | dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n", |
712 | __func__, __LINE__, dev->priv->work.trigger); | 815 | __func__, __LINE__, priv->rx_list.work.trigger); |
713 | dev->priv->work.trigger = 0; | 816 | priv->rx_list.work.trigger = 0; |
714 | schedule_work(&dev->priv->work.work); | 817 | schedule_work(&priv->rx_list.work.work); |
715 | } | 818 | } |
716 | spin_unlock_irqrestore(&dev->priv->work.lock, flags); | 819 | |
717 | return 0; | 820 | spin_unlock_irqrestore(&priv->rx_list.lock, flags); |
821 | return result; | ||
718 | } | 822 | } |
719 | 823 | ||
720 | static int ps3_vuart_handle_interrupt_disconnect( | 824 | static int ps3_vuart_handle_interrupt_disconnect( |
721 | struct ps3_vuart_port_device *dev) | 825 | struct ps3_system_bus_device *dev) |
722 | { | 826 | { |
723 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 827 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
724 | BUG_ON("no support"); | 828 | BUG_ON("no support"); |
@@ -733,9 +837,10 @@ static int ps3_vuart_handle_interrupt_disconnect( | |||
733 | * stage handler after one iteration. | 837 | * stage handler after one iteration. |
734 | */ | 838 | */ |
735 | 839 | ||
736 | static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) | 840 | static int ps3_vuart_handle_port_interrupt(struct ps3_system_bus_device *dev) |
737 | { | 841 | { |
738 | int result; | 842 | int result; |
843 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
739 | unsigned long status; | 844 | unsigned long status; |
740 | 845 | ||
741 | result = ps3_vuart_get_interrupt_status(dev, &status); | 846 | result = ps3_vuart_get_interrupt_status(dev, &status); |
@@ -747,21 +852,21 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) | |||
747 | status); | 852 | status); |
748 | 853 | ||
749 | if (status & INTERRUPT_MASK_DISCONNECT) { | 854 | if (status & INTERRUPT_MASK_DISCONNECT) { |
750 | dev->priv->stats.disconnect_interrupts++; | 855 | priv->stats.disconnect_interrupts++; |
751 | result = ps3_vuart_handle_interrupt_disconnect(dev); | 856 | result = ps3_vuart_handle_interrupt_disconnect(dev); |
752 | if (result) | 857 | if (result) |
753 | ps3_vuart_disable_interrupt_disconnect(dev); | 858 | ps3_vuart_disable_interrupt_disconnect(dev); |
754 | } | 859 | } |
755 | 860 | ||
756 | if (status & INTERRUPT_MASK_TX) { | 861 | if (status & INTERRUPT_MASK_TX) { |
757 | dev->priv->stats.tx_interrupts++; | 862 | priv->stats.tx_interrupts++; |
758 | result = ps3_vuart_handle_interrupt_tx(dev); | 863 | result = ps3_vuart_handle_interrupt_tx(dev); |
759 | if (result) | 864 | if (result) |
760 | ps3_vuart_disable_interrupt_tx(dev); | 865 | ps3_vuart_disable_interrupt_tx(dev); |
761 | } | 866 | } |
762 | 867 | ||
763 | if (status & INTERRUPT_MASK_RX) { | 868 | if (status & INTERRUPT_MASK_RX) { |
764 | dev->priv->stats.rx_interrupts++; | 869 | priv->stats.rx_interrupts++; |
765 | result = ps3_vuart_handle_interrupt_rx(dev); | 870 | result = ps3_vuart_handle_interrupt_rx(dev); |
766 | if (result) | 871 | if (result) |
767 | ps3_vuart_disable_interrupt_rx(dev); | 872 | ps3_vuart_disable_interrupt_rx(dev); |
@@ -771,11 +876,11 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev) | |||
771 | } | 876 | } |
772 | 877 | ||
773 | struct vuart_bus_priv { | 878 | struct vuart_bus_priv { |
774 | const struct ports_bmp bmp; | 879 | struct ports_bmp *bmp; |
775 | unsigned int virq; | 880 | unsigned int virq; |
776 | struct semaphore probe_mutex; | 881 | struct semaphore probe_mutex; |
777 | int use_count; | 882 | int use_count; |
778 | struct ps3_vuart_port_device *devices[PORT_COUNT]; | 883 | struct ps3_system_bus_device *devices[PORT_COUNT]; |
779 | } static vuart_bus_priv; | 884 | } static vuart_bus_priv; |
780 | 885 | ||
781 | /** | 886 | /** |
@@ -788,17 +893,16 @@ struct vuart_bus_priv { | |||
788 | 893 | ||
789 | static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private) | 894 | static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private) |
790 | { | 895 | { |
791 | struct vuart_bus_priv *bus_priv; | 896 | struct vuart_bus_priv *bus_priv = _private; |
792 | 897 | ||
793 | BUG_ON(!_private); | 898 | BUG_ON(!bus_priv); |
794 | bus_priv = (struct vuart_bus_priv *)_private; | ||
795 | 899 | ||
796 | while (1) { | 900 | while (1) { |
797 | unsigned int port; | 901 | unsigned int port; |
798 | 902 | ||
799 | dump_ports_bmp(&bus_priv->bmp); | 903 | dump_ports_bmp(bus_priv->bmp); |
800 | 904 | ||
801 | port = (BITS_PER_LONG - 1) - __ilog2(bus_priv->bmp.status); | 905 | port = (BITS_PER_LONG - 1) - __ilog2(bus_priv->bmp->status); |
802 | 906 | ||
803 | if (port == BITS_PER_LONG) | 907 | if (port == BITS_PER_LONG) |
804 | break; | 908 | break; |
@@ -812,100 +916,144 @@ static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private) | |||
812 | return IRQ_HANDLED; | 916 | return IRQ_HANDLED; |
813 | } | 917 | } |
814 | 918 | ||
815 | static int ps3_vuart_match(struct device *_dev, struct device_driver *_drv) | 919 | static int ps3_vuart_bus_interrupt_get(void) |
816 | { | 920 | { |
817 | int result; | 921 | int result; |
818 | struct ps3_vuart_port_driver *drv = to_ps3_vuart_port_driver(_drv); | ||
819 | struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); | ||
820 | 922 | ||
821 | result = dev->match_id == drv->match_id; | 923 | pr_debug(" -> %s:%d\n", __func__, __LINE__); |
924 | |||
925 | vuart_bus_priv.use_count++; | ||
926 | |||
927 | BUG_ON(vuart_bus_priv.use_count > 2); | ||
928 | |||
929 | if (vuart_bus_priv.use_count != 1) { | ||
930 | return 0; | ||
931 | } | ||
932 | |||
933 | BUG_ON(vuart_bus_priv.bmp); | ||
934 | |||
935 | vuart_bus_priv.bmp = kzalloc(sizeof(struct ports_bmp), GFP_KERNEL); | ||
936 | |||
937 | if (!vuart_bus_priv.bmp) { | ||
938 | pr_debug("%s:%d: kzalloc failed.\n", __func__, __LINE__); | ||
939 | result = -ENOMEM; | ||
940 | goto fail_bmp_malloc; | ||
941 | } | ||
942 | |||
943 | result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY, vuart_bus_priv.bmp, | ||
944 | &vuart_bus_priv.virq); | ||
945 | |||
946 | if (result) { | ||
947 | pr_debug("%s:%d: ps3_vuart_irq_setup failed (%d)\n", | ||
948 | __func__, __LINE__, result); | ||
949 | result = -EPERM; | ||
950 | goto fail_alloc_irq; | ||
951 | } | ||
952 | |||
953 | result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler, | ||
954 | IRQF_DISABLED, "vuart", &vuart_bus_priv); | ||
822 | 955 | ||
823 | dev_info(&dev->core, "%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__, | 956 | if (result) { |
824 | __LINE__, dev->match_id, dev->core.bus_id, drv->match_id, | 957 | pr_debug("%s:%d: request_irq failed (%d)\n", |
825 | drv->core.name, (result ? "match" : "miss")); | 958 | __func__, __LINE__, result); |
959 | goto fail_request_irq; | ||
960 | } | ||
826 | 961 | ||
962 | pr_debug(" <- %s:%d: ok\n", __func__, __LINE__); | ||
827 | return result; | 963 | return result; |
964 | |||
965 | fail_request_irq: | ||
966 | ps3_vuart_irq_destroy(vuart_bus_priv.virq); | ||
967 | vuart_bus_priv.virq = NO_IRQ; | ||
968 | fail_alloc_irq: | ||
969 | kfree(vuart_bus_priv.bmp); | ||
970 | vuart_bus_priv.bmp = NULL; | ||
971 | fail_bmp_malloc: | ||
972 | vuart_bus_priv.use_count--; | ||
973 | pr_debug(" <- %s:%d: failed\n", __func__, __LINE__); | ||
974 | return result; | ||
975 | } | ||
976 | |||
977 | static int ps3_vuart_bus_interrupt_put(void) | ||
978 | { | ||
979 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
980 | |||
981 | vuart_bus_priv.use_count--; | ||
982 | |||
983 | BUG_ON(vuart_bus_priv.use_count < 0); | ||
984 | |||
985 | if (vuart_bus_priv.use_count != 0) | ||
986 | return 0; | ||
987 | |||
988 | free_irq(vuart_bus_priv.virq, &vuart_bus_priv); | ||
989 | |||
990 | ps3_vuart_irq_destroy(vuart_bus_priv.virq); | ||
991 | vuart_bus_priv.virq = NO_IRQ; | ||
992 | |||
993 | kfree(vuart_bus_priv.bmp); | ||
994 | vuart_bus_priv.bmp = NULL; | ||
995 | |||
996 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
997 | return 0; | ||
828 | } | 998 | } |
829 | 999 | ||
830 | static int ps3_vuart_probe(struct device *_dev) | 1000 | static int ps3_vuart_probe(struct ps3_system_bus_device *dev) |
831 | { | 1001 | { |
832 | int result; | 1002 | int result; |
833 | unsigned int port_number; | 1003 | struct ps3_vuart_port_driver *drv; |
834 | struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); | 1004 | struct ps3_vuart_port_priv *priv = NULL; |
835 | struct ps3_vuart_port_driver *drv = | ||
836 | to_ps3_vuart_port_driver(_dev->driver); | ||
837 | 1005 | ||
838 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 1006 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
839 | 1007 | ||
1008 | drv = ps3_system_bus_dev_to_vuart_drv(dev); | ||
1009 | |||
1010 | dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__, | ||
1011 | drv->core.core.name); | ||
1012 | |||
840 | BUG_ON(!drv); | 1013 | BUG_ON(!drv); |
841 | 1014 | ||
842 | down(&vuart_bus_priv.probe_mutex); | 1015 | if (dev->port_number >= PORT_COUNT) { |
1016 | BUG(); | ||
1017 | return -EINVAL; | ||
1018 | } | ||
843 | 1019 | ||
844 | /* Setup vuart_bus_priv.devices[]. */ | 1020 | down(&vuart_bus_priv.probe_mutex); |
845 | 1021 | ||
846 | result = ps3_vuart_match_id_to_port(dev->match_id, | 1022 | result = ps3_vuart_bus_interrupt_get(); |
847 | &port_number); | ||
848 | 1023 | ||
849 | if (result) { | 1024 | if (result) |
850 | dev_dbg(&dev->core, "%s:%d: unknown match_id (%d)\n", | 1025 | goto fail_setup_interrupt; |
851 | __func__, __LINE__, dev->match_id); | ||
852 | result = -EINVAL; | ||
853 | goto fail_match; | ||
854 | } | ||
855 | 1026 | ||
856 | if (vuart_bus_priv.devices[port_number]) { | 1027 | if (vuart_bus_priv.devices[dev->port_number]) { |
857 | dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__, | 1028 | dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__, |
858 | __LINE__, port_number); | 1029 | __LINE__, dev->port_number); |
859 | result = -EBUSY; | 1030 | result = -EBUSY; |
860 | goto fail_match; | 1031 | goto fail_busy; |
861 | } | 1032 | } |
862 | 1033 | ||
863 | vuart_bus_priv.devices[port_number] = dev; | 1034 | vuart_bus_priv.devices[dev->port_number] = dev; |
864 | 1035 | ||
865 | /* Setup dev->priv. */ | 1036 | /* Setup dev->driver_priv. */ |
866 | 1037 | ||
867 | dev->priv = kzalloc(sizeof(struct ps3_vuart_port_priv), GFP_KERNEL); | 1038 | dev->driver_priv = kzalloc(sizeof(struct ps3_vuart_port_priv), |
1039 | GFP_KERNEL); | ||
868 | 1040 | ||
869 | if (!dev->priv) { | 1041 | if (!dev->driver_priv) { |
870 | result = -ENOMEM; | 1042 | result = -ENOMEM; |
871 | goto fail_alloc; | 1043 | goto fail_dev_malloc; |
872 | } | 1044 | } |
873 | 1045 | ||
874 | dev->priv->port_number = port_number; | 1046 | priv = to_port_priv(dev); |
875 | |||
876 | INIT_LIST_HEAD(&dev->priv->tx_list.head); | ||
877 | spin_lock_init(&dev->priv->tx_list.lock); | ||
878 | 1047 | ||
879 | INIT_LIST_HEAD(&dev->priv->rx_list.head); | 1048 | INIT_LIST_HEAD(&priv->tx_list.head); |
880 | spin_lock_init(&dev->priv->rx_list.lock); | 1049 | spin_lock_init(&priv->tx_list.lock); |
881 | 1050 | ||
882 | INIT_WORK(&dev->priv->work.work, NULL); | 1051 | INIT_LIST_HEAD(&priv->rx_list.head); |
883 | spin_lock_init(&dev->priv->work.lock); | 1052 | spin_lock_init(&priv->rx_list.lock); |
884 | dev->priv->work.trigger = 0; | ||
885 | dev->priv->work.dev = dev; | ||
886 | 1053 | ||
887 | if (++vuart_bus_priv.use_count == 1) { | 1054 | INIT_WORK(&priv->rx_list.work.work, NULL); |
888 | 1055 | priv->rx_list.work.trigger = 0; | |
889 | result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY, | 1056 | priv->rx_list.work.dev = dev; |
890 | (void*)&vuart_bus_priv.bmp.status, &vuart_bus_priv.virq); | ||
891 | |||
892 | if (result) { | ||
893 | dev_dbg(&dev->core, | ||
894 | "%s:%d: ps3_vuart_irq_setup failed (%d)\n", | ||
895 | __func__, __LINE__, result); | ||
896 | result = -EPERM; | ||
897 | goto fail_alloc_irq; | ||
898 | } | ||
899 | |||
900 | result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler, | ||
901 | IRQF_DISABLED, "vuart", &vuart_bus_priv); | ||
902 | |||
903 | if (result) { | ||
904 | dev_info(&dev->core, "%s:%d: request_irq failed (%d)\n", | ||
905 | __func__, __LINE__, result); | ||
906 | goto fail_request_irq; | ||
907 | } | ||
908 | } | ||
909 | 1057 | ||
910 | /* clear stale pending interrupts */ | 1058 | /* clear stale pending interrupts */ |
911 | 1059 | ||
@@ -936,150 +1084,158 @@ static int ps3_vuart_probe(struct device *_dev) | |||
936 | 1084 | ||
937 | fail_probe: | 1085 | fail_probe: |
938 | ps3_vuart_set_interrupt_mask(dev, 0); | 1086 | ps3_vuart_set_interrupt_mask(dev, 0); |
939 | fail_request_irq: | 1087 | kfree(dev->driver_priv); |
940 | ps3_vuart_irq_destroy(vuart_bus_priv.virq); | 1088 | dev->driver_priv = NULL; |
941 | vuart_bus_priv.virq = NO_IRQ; | 1089 | fail_dev_malloc: |
942 | fail_alloc_irq: | 1090 | vuart_bus_priv.devices[dev->port_number] = NULL; |
943 | --vuart_bus_priv.use_count; | 1091 | fail_busy: |
944 | kfree(dev->priv); | 1092 | ps3_vuart_bus_interrupt_put(); |
945 | dev->priv = NULL; | 1093 | fail_setup_interrupt: |
946 | fail_alloc: | ||
947 | vuart_bus_priv.devices[port_number] = NULL; | ||
948 | fail_match: | ||
949 | up(&vuart_bus_priv.probe_mutex); | 1094 | up(&vuart_bus_priv.probe_mutex); |
950 | dev_dbg(&dev->core, "%s:%d failed\n", __func__, __LINE__); | 1095 | dev_dbg(&dev->core, "%s:%d: failed\n", __func__, __LINE__); |
951 | return result; | 1096 | return result; |
952 | } | 1097 | } |
953 | 1098 | ||
954 | static int ps3_vuart_remove(struct device *_dev) | 1099 | /** |
1100 | * ps3_vuart_cleanup - common cleanup helper. | ||
1101 | * @dev: The struct ps3_system_bus_device instance. | ||
1102 | * | ||
1103 | * Cleans interrupts and HV resources. Must be called with | ||
1104 | * vuart_bus_priv.probe_mutex held. Used by ps3_vuart_remove and | ||
1105 | * ps3_vuart_shutdown. After this call, polled reading will still work. | ||
1106 | */ | ||
1107 | |||
1108 | static int ps3_vuart_cleanup(struct ps3_system_bus_device *dev) | ||
955 | { | 1109 | { |
956 | struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); | 1110 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); |
957 | struct ps3_vuart_port_driver *drv = | 1111 | |
958 | to_ps3_vuart_port_driver(_dev->driver); | 1112 | ps3_vuart_cancel_async(dev); |
1113 | ps3_vuart_set_interrupt_mask(dev, 0); | ||
1114 | ps3_vuart_bus_interrupt_put(); | ||
1115 | return 0; | ||
1116 | } | ||
1117 | |||
1118 | /** | ||
1119 | * ps3_vuart_remove - Completely clean the device instance. | ||
1120 | * @dev: The struct ps3_system_bus_device instance. | ||
1121 | * | ||
1122 | * Cleans all memory, interrupts and HV resources. After this call the | ||
1123 | * device can no longer be used. | ||
1124 | */ | ||
1125 | |||
1126 | static int ps3_vuart_remove(struct ps3_system_bus_device *dev) | ||
1127 | { | ||
1128 | struct ps3_vuart_port_priv *priv = to_port_priv(dev); | ||
1129 | struct ps3_vuart_port_driver *drv; | ||
1130 | |||
1131 | BUG_ON(!dev); | ||
959 | 1132 | ||
960 | down(&vuart_bus_priv.probe_mutex); | 1133 | down(&vuart_bus_priv.probe_mutex); |
961 | 1134 | ||
962 | dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__, | 1135 | dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__, |
963 | dev->core.bus_id); | 1136 | dev->match_id); |
964 | 1137 | ||
965 | BUG_ON(vuart_bus_priv.use_count < 1); | 1138 | if (!dev->core.driver) { |
1139 | dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__, | ||
1140 | __LINE__); | ||
1141 | up(&vuart_bus_priv.probe_mutex); | ||
1142 | return 0; | ||
1143 | } | ||
966 | 1144 | ||
967 | if (drv->remove) | 1145 | drv = ps3_system_bus_dev_to_vuart_drv(dev); |
968 | drv->remove(dev); | ||
969 | else | ||
970 | dev_dbg(&dev->core, "%s:%d: %s no remove method\n", __func__, | ||
971 | __LINE__, dev->core.bus_id); | ||
972 | 1146 | ||
973 | vuart_bus_priv.devices[dev->priv->port_number] = NULL; | 1147 | BUG_ON(!drv); |
974 | 1148 | ||
975 | if (--vuart_bus_priv.use_count == 0) { | 1149 | if (drv->remove) { |
1150 | drv->remove(dev); | ||
1151 | } else { | ||
1152 | dev_dbg(&dev->core, "%s:%d: no remove method\n", __func__, | ||
1153 | __LINE__); | ||
976 | BUG(); | 1154 | BUG(); |
977 | free_irq(vuart_bus_priv.virq, &vuart_bus_priv); | ||
978 | ps3_vuart_irq_destroy(vuart_bus_priv.virq); | ||
979 | vuart_bus_priv.virq = NO_IRQ; | ||
980 | } | 1155 | } |
981 | 1156 | ||
982 | kfree(dev->priv); | 1157 | ps3_vuart_cleanup(dev); |
983 | dev->priv = NULL; | 1158 | |
1159 | vuart_bus_priv.devices[dev->port_number] = NULL; | ||
1160 | kfree(priv); | ||
1161 | priv = NULL; | ||
984 | 1162 | ||
1163 | dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); | ||
985 | up(&vuart_bus_priv.probe_mutex); | 1164 | up(&vuart_bus_priv.probe_mutex); |
986 | return 0; | 1165 | return 0; |
987 | } | 1166 | } |
988 | 1167 | ||
989 | static void ps3_vuart_shutdown(struct device *_dev) | ||
990 | { | ||
991 | struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); | ||
992 | struct ps3_vuart_port_driver *drv = | ||
993 | to_ps3_vuart_port_driver(_dev->driver); | ||
994 | |||
995 | dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__, | ||
996 | dev->core.bus_id); | ||
997 | |||
998 | if (drv->shutdown) | ||
999 | drv->shutdown(dev); | ||
1000 | else | ||
1001 | dev_dbg(&dev->core, "%s:%d: %s no shutdown method\n", __func__, | ||
1002 | __LINE__, dev->core.bus_id); | ||
1003 | } | ||
1004 | |||
1005 | /** | 1168 | /** |
1006 | * ps3_vuart_bus - The vuart bus instance. | 1169 | * ps3_vuart_shutdown - Cleans interrupts and HV resources. |
1170 | * @dev: The struct ps3_system_bus_device instance. | ||
1007 | * | 1171 | * |
1008 | * The vuart is managed as a bus that port devices connect to. | 1172 | * Cleans interrupts and HV resources. After this call the |
1173 | * device can still be used in polling mode. This behavior required | ||
1174 | * by sys-manager to be able to complete the device power operation | ||
1175 | * sequence. | ||
1009 | */ | 1176 | */ |
1010 | 1177 | ||
1011 | struct bus_type ps3_vuart_bus = { | 1178 | static int ps3_vuart_shutdown(struct ps3_system_bus_device *dev) |
1012 | .name = "ps3_vuart", | ||
1013 | .match = ps3_vuart_match, | ||
1014 | .probe = ps3_vuart_probe, | ||
1015 | .remove = ps3_vuart_remove, | ||
1016 | .shutdown = ps3_vuart_shutdown, | ||
1017 | }; | ||
1018 | |||
1019 | int __init ps3_vuart_bus_init(void) | ||
1020 | { | 1179 | { |
1021 | int result; | 1180 | struct ps3_vuart_port_driver *drv; |
1022 | 1181 | ||
1023 | pr_debug("%s:%d:\n", __func__, __LINE__); | 1182 | BUG_ON(!dev); |
1024 | 1183 | ||
1025 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | 1184 | down(&vuart_bus_priv.probe_mutex); |
1026 | return -ENODEV; | ||
1027 | 1185 | ||
1028 | init_MUTEX(&vuart_bus_priv.probe_mutex); | 1186 | dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__, |
1029 | result = bus_register(&ps3_vuart_bus); | 1187 | dev->match_id); |
1030 | BUG_ON(result); | ||
1031 | 1188 | ||
1032 | return result; | 1189 | if (!dev->core.driver) { |
1033 | } | 1190 | dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__, |
1191 | __LINE__); | ||
1192 | up(&vuart_bus_priv.probe_mutex); | ||
1193 | return 0; | ||
1194 | } | ||
1034 | 1195 | ||
1035 | void __exit ps3_vuart_bus_exit(void) | 1196 | drv = ps3_system_bus_dev_to_vuart_drv(dev); |
1036 | { | ||
1037 | pr_debug("%s:%d:\n", __func__, __LINE__); | ||
1038 | bus_unregister(&ps3_vuart_bus); | ||
1039 | } | ||
1040 | 1197 | ||
1041 | core_initcall(ps3_vuart_bus_init); | 1198 | BUG_ON(!drv); |
1042 | module_exit(ps3_vuart_bus_exit); | ||
1043 | 1199 | ||
1044 | /** | 1200 | if (drv->shutdown) |
1045 | * ps3_vuart_port_release_device - Remove a vuart port device. | 1201 | drv->shutdown(dev); |
1046 | */ | 1202 | else if (drv->remove) { |
1203 | dev_dbg(&dev->core, "%s:%d: no shutdown, calling remove\n", | ||
1204 | __func__, __LINE__); | ||
1205 | drv->remove(dev); | ||
1206 | } else { | ||
1207 | dev_dbg(&dev->core, "%s:%d: no shutdown method\n", __func__, | ||
1208 | __LINE__); | ||
1209 | BUG(); | ||
1210 | } | ||
1047 | 1211 | ||
1048 | static void ps3_vuart_port_release_device(struct device *_dev) | 1212 | ps3_vuart_cleanup(dev); |
1049 | { | ||
1050 | #if defined(DEBUG) | ||
1051 | struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev); | ||
1052 | 1213 | ||
1053 | dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); | 1214 | dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); |
1054 | 1215 | ||
1055 | BUG_ON(dev->priv && "forgot to free"); | 1216 | up(&vuart_bus_priv.probe_mutex); |
1056 | memset(&dev->core, 0, sizeof(dev->core)); | 1217 | return 0; |
1057 | #endif | ||
1058 | } | 1218 | } |
1059 | 1219 | ||
1060 | /** | 1220 | static int __init ps3_vuart_bus_init(void) |
1061 | * ps3_vuart_port_device_register - Add a vuart port device. | ||
1062 | */ | ||
1063 | |||
1064 | int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev) | ||
1065 | { | 1221 | { |
1066 | static unsigned int dev_count = 1; | 1222 | pr_debug("%s:%d:\n", __func__, __LINE__); |
1067 | |||
1068 | BUG_ON(dev->priv && "forgot to free"); | ||
1069 | 1223 | ||
1070 | dev->core.parent = NULL; | 1224 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) |
1071 | dev->core.bus = &ps3_vuart_bus; | 1225 | return -ENODEV; |
1072 | dev->core.release = ps3_vuart_port_release_device; | ||
1073 | 1226 | ||
1074 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x", | 1227 | init_MUTEX(&vuart_bus_priv.probe_mutex); |
1075 | dev_count++); | ||
1076 | 1228 | ||
1077 | dev_dbg(&dev->core, "%s:%d register\n", __func__, __LINE__); | 1229 | return 0; |
1230 | } | ||
1078 | 1231 | ||
1079 | return device_register(&dev->core); | 1232 | static void __exit ps3_vuart_bus_exit(void) |
1233 | { | ||
1234 | pr_debug("%s:%d:\n", __func__, __LINE__); | ||
1080 | } | 1235 | } |
1081 | 1236 | ||
1082 | EXPORT_SYMBOL_GPL(ps3_vuart_port_device_register); | 1237 | core_initcall(ps3_vuart_bus_init); |
1238 | module_exit(ps3_vuart_bus_exit); | ||
1083 | 1239 | ||
1084 | /** | 1240 | /** |
1085 | * ps3_vuart_port_driver_register - Add a vuart port device driver. | 1241 | * ps3_vuart_port_driver_register - Add a vuart port device driver. |
@@ -1089,12 +1245,18 @@ int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv) | |||
1089 | { | 1245 | { |
1090 | int result; | 1246 | int result; |
1091 | 1247 | ||
1092 | pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name); | 1248 | pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.core.name); |
1093 | drv->core.bus = &ps3_vuart_bus; | 1249 | |
1094 | result = driver_register(&drv->core); | 1250 | BUG_ON(!drv->core.match_id); |
1251 | BUG_ON(!drv->core.core.name); | ||
1252 | |||
1253 | drv->core.probe = ps3_vuart_probe; | ||
1254 | drv->core.remove = ps3_vuart_remove; | ||
1255 | drv->core.shutdown = ps3_vuart_shutdown; | ||
1256 | |||
1257 | result = ps3_system_bus_driver_register(&drv->core); | ||
1095 | return result; | 1258 | return result; |
1096 | } | 1259 | } |
1097 | |||
1098 | EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register); | 1260 | EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register); |
1099 | 1261 | ||
1100 | /** | 1262 | /** |
@@ -1103,8 +1265,7 @@ EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register); | |||
1103 | 1265 | ||
1104 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv) | 1266 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv) |
1105 | { | 1267 | { |
1106 | pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name); | 1268 | pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.core.name); |
1107 | driver_unregister(&drv->core); | 1269 | ps3_system_bus_driver_unregister(&drv->core); |
1108 | } | 1270 | } |
1109 | |||
1110 | EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_unregister); | 1271 | EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_unregister); |
diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h index 1be992d568c8..eb7f6d94a890 100644 --- a/drivers/ps3/vuart.h +++ b/drivers/ps3/vuart.h | |||
@@ -34,29 +34,7 @@ struct ps3_vuart_stats { | |||
34 | struct ps3_vuart_work { | 34 | struct ps3_vuart_work { |
35 | struct work_struct work; | 35 | struct work_struct work; |
36 | unsigned long trigger; | 36 | unsigned long trigger; |
37 | spinlock_t lock; | 37 | struct ps3_system_bus_device *dev; /* to convert work to device */ |
38 | struct ps3_vuart_port_device* dev; /* to convert work to device */ | ||
39 | }; | ||
40 | |||
41 | /** | ||
42 | * struct ps3_vuart_port_priv - private vuart device data. | ||
43 | */ | ||
44 | |||
45 | struct ps3_vuart_port_priv { | ||
46 | unsigned int port_number; | ||
47 | u64 interrupt_mask; | ||
48 | |||
49 | struct { | ||
50 | spinlock_t lock; | ||
51 | struct list_head head; | ||
52 | } tx_list; | ||
53 | struct { | ||
54 | unsigned long bytes_held; | ||
55 | spinlock_t lock; | ||
56 | struct list_head head; | ||
57 | } rx_list; | ||
58 | struct ps3_vuart_stats stats; | ||
59 | struct ps3_vuart_work work; | ||
60 | }; | 38 | }; |
61 | 39 | ||
62 | /** | 40 | /** |
@@ -64,32 +42,30 @@ struct ps3_vuart_port_priv { | |||
64 | */ | 42 | */ |
65 | 43 | ||
66 | struct ps3_vuart_port_driver { | 44 | struct ps3_vuart_port_driver { |
67 | enum ps3_match_id match_id; | 45 | struct ps3_system_bus_driver core; |
68 | struct device_driver core; | 46 | int (*probe)(struct ps3_system_bus_device *); |
69 | int (*probe)(struct ps3_vuart_port_device *); | 47 | int (*remove)(struct ps3_system_bus_device *); |
70 | int (*remove)(struct ps3_vuart_port_device *); | 48 | void (*shutdown)(struct ps3_system_bus_device *); |
71 | void (*shutdown)(struct ps3_vuart_port_device *); | 49 | void (*work)(struct ps3_system_bus_device *); |
72 | int (*tx_event)(struct ps3_vuart_port_device *dev); | 50 | /* int (*tx_event)(struct ps3_system_bus_device *dev); */ |
73 | int (*rx_event)(struct ps3_vuart_port_device *dev); | 51 | /* int (*rx_event)(struct ps3_system_bus_device *dev); */ |
74 | int (*disconnect_event)(struct ps3_vuart_port_device *dev); | 52 | /* int (*disconnect_event)(struct ps3_system_bus_device *dev); */ |
75 | /* int (*suspend)(struct ps3_vuart_port_device *, pm_message_t); */ | 53 | /* int (*suspend)(struct ps3_system_bus_device *, pm_message_t); */ |
76 | /* int (*resume)(struct ps3_vuart_port_device *); */ | 54 | /* int (*resume)(struct ps3_system_bus_device *); */ |
77 | }; | 55 | }; |
78 | 56 | ||
79 | int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv); | 57 | int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv); |
80 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv); | 58 | void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv); |
81 | 59 | ||
82 | static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver( | 60 | static inline struct ps3_vuart_port_driver * |
83 | struct device_driver *_drv) | 61 | ps3_system_bus_dev_to_vuart_drv(struct ps3_system_bus_device *_dev) |
84 | { | ||
85 | return container_of(_drv, struct ps3_vuart_port_driver, core); | ||
86 | } | ||
87 | static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device( | ||
88 | struct device *_dev) | ||
89 | { | 62 | { |
90 | return container_of(_dev, struct ps3_vuart_port_device, core); | 63 | struct ps3_system_bus_driver *sbd = |
64 | ps3_system_bus_dev_to_system_bus_drv(_dev); | ||
65 | BUG_ON(!sbd); | ||
66 | return container_of(sbd, struct ps3_vuart_port_driver, core); | ||
91 | } | 67 | } |
92 | static inline struct ps3_vuart_port_device *ps3_vuart_work_to_port_device( | 68 | static inline struct ps3_system_bus_device *ps3_vuart_work_to_system_bus_dev( |
93 | struct work_struct *_work) | 69 | struct work_struct *_work) |
94 | { | 70 | { |
95 | struct ps3_vuart_work *vw = container_of(_work, struct ps3_vuart_work, | 71 | struct ps3_vuart_work *vw = container_of(_work, struct ps3_vuart_work, |
@@ -97,14 +73,13 @@ static inline struct ps3_vuart_port_device *ps3_vuart_work_to_port_device( | |||
97 | return vw->dev; | 73 | return vw->dev; |
98 | } | 74 | } |
99 | 75 | ||
100 | int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf, | 76 | int ps3_vuart_write(struct ps3_system_bus_device *dev, const void *buf, |
101 | unsigned int bytes); | ||
102 | int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf, | ||
103 | unsigned int bytes); | 77 | unsigned int bytes); |
104 | int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func, | 78 | int ps3_vuart_read(struct ps3_system_bus_device *dev, void *buf, |
105 | unsigned int bytes); | 79 | unsigned int bytes); |
106 | void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev); | 80 | int ps3_vuart_read_async(struct ps3_system_bus_device *dev, unsigned int bytes); |
107 | void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev, | 81 | void ps3_vuart_cancel_async(struct ps3_system_bus_device *dev); |
82 | void ps3_vuart_clear_rx_bytes(struct ps3_system_bus_device *dev, | ||
108 | unsigned int bytes); | 83 | unsigned int bytes); |
109 | 84 | ||
110 | #endif | 85 | #endif |
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 4e4c10a7fd3a..83b071b6ece4 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -246,7 +246,7 @@ comment "Platform RTC drivers" | |||
246 | config RTC_DRV_CMOS | 246 | config RTC_DRV_CMOS |
247 | tristate "PC-style 'CMOS'" | 247 | tristate "PC-style 'CMOS'" |
248 | depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \ | 248 | depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \ |
249 | || M32R || ATARI || POWERPC || MIPS) | 249 | || M32R || ATARI || PPC || MIPS) |
250 | help | 250 | help |
251 | Say "yes" here to get direct support for the real time clock | 251 | Say "yes" here to get direct support for the real time clock |
252 | found in every PC or ACPI-based system, and some other boards. | 252 | found in every PC or ACPI-based system, and some other boards. |
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index b63ff8dd7304..cefde58dbad2 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c | |||
@@ -678,7 +678,7 @@ static int cpm_uart_tx_pump(struct uart_port *port) | |||
678 | } | 678 | } |
679 | bdp->cbd_datlen = count; | 679 | bdp->cbd_datlen = count; |
680 | bdp->cbd_sc |= BD_SC_READY; | 680 | bdp->cbd_sc |= BD_SC_READY; |
681 | __asm__("eieio"); | 681 | eieio(); |
682 | /* Get next BD. */ | 682 | /* Get next BD. */ |
683 | if (bdp->cbd_sc & BD_SC_WRAP) | 683 | if (bdp->cbd_sc & BD_SC_WRAP) |
684 | bdp = pinfo->tx_bd_base; | 684 | bdp = pinfo->tx_bd_base; |
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c index 7ffdaeaf0545..a64d85821996 100644 --- a/drivers/serial/of_serial.c +++ b/drivers/serial/of_serial.c | |||
@@ -17,6 +17,11 @@ | |||
17 | #include <asm/of_platform.h> | 17 | #include <asm/of_platform.h> |
18 | #include <asm/prom.h> | 18 | #include <asm/prom.h> |
19 | 19 | ||
20 | struct of_serial_info { | ||
21 | int type; | ||
22 | int line; | ||
23 | }; | ||
24 | |||
20 | /* | 25 | /* |
21 | * Fill a struct uart_port for a given device node | 26 | * Fill a struct uart_port for a given device node |
22 | */ | 27 | */ |
@@ -62,6 +67,7 @@ static int __devinit of_platform_serial_setup(struct of_device *ofdev, | |||
62 | static int __devinit of_platform_serial_probe(struct of_device *ofdev, | 67 | static int __devinit of_platform_serial_probe(struct of_device *ofdev, |
63 | const struct of_device_id *id) | 68 | const struct of_device_id *id) |
64 | { | 69 | { |
70 | struct of_serial_info *info; | ||
65 | struct uart_port port; | 71 | struct uart_port port; |
66 | int port_type; | 72 | int port_type; |
67 | int ret; | 73 | int ret; |
@@ -69,30 +75,35 @@ static int __devinit of_platform_serial_probe(struct of_device *ofdev, | |||
69 | if (of_find_property(ofdev->node, "used-by-rtas", NULL)) | 75 | if (of_find_property(ofdev->node, "used-by-rtas", NULL)) |
70 | return -EBUSY; | 76 | return -EBUSY; |
71 | 77 | ||
78 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
79 | if (info == NULL) | ||
80 | return -ENOMEM; | ||
81 | |||
72 | port_type = (unsigned long)id->data; | 82 | port_type = (unsigned long)id->data; |
73 | ret = of_platform_serial_setup(ofdev, port_type, &port); | 83 | ret = of_platform_serial_setup(ofdev, port_type, &port); |
74 | if (ret) | 84 | if (ret) |
75 | goto out; | 85 | goto out; |
76 | 86 | ||
77 | switch (port_type) { | 87 | switch (port_type) { |
78 | case PORT_UNKNOWN: | ||
79 | dev_info(&ofdev->dev, "Unknown serial port found, " | ||
80 | "attempting to use 8250 driver\n"); | ||
81 | /* fallthrough */ | ||
82 | case PORT_8250 ... PORT_MAX_8250: | 88 | case PORT_8250 ... PORT_MAX_8250: |
83 | ret = serial8250_register_port(&port); | 89 | ret = serial8250_register_port(&port); |
84 | break; | 90 | break; |
85 | default: | 91 | default: |
86 | /* need to add code for these */ | 92 | /* need to add code for these */ |
93 | case PORT_UNKNOWN: | ||
94 | dev_info(&ofdev->dev, "Unknown serial port found, ignored\n"); | ||
87 | ret = -ENODEV; | 95 | ret = -ENODEV; |
88 | break; | 96 | break; |
89 | } | 97 | } |
90 | if (ret < 0) | 98 | if (ret < 0) |
91 | goto out; | 99 | goto out; |
92 | 100 | ||
93 | ofdev->dev.driver_data = (void *)(unsigned long)ret; | 101 | info->type = port_type; |
102 | info->line = ret; | ||
103 | ofdev->dev.driver_data = info; | ||
94 | return 0; | 104 | return 0; |
95 | out: | 105 | out: |
106 | kfree(info); | ||
96 | irq_dispose_mapping(port.irq); | 107 | irq_dispose_mapping(port.irq); |
97 | return ret; | 108 | return ret; |
98 | } | 109 | } |
@@ -102,8 +113,16 @@ out: | |||
102 | */ | 113 | */ |
103 | static int of_platform_serial_remove(struct of_device *ofdev) | 114 | static int of_platform_serial_remove(struct of_device *ofdev) |
104 | { | 115 | { |
105 | int line = (unsigned long)ofdev->dev.driver_data; | 116 | struct of_serial_info *info = ofdev->dev.driver_data; |
106 | serial8250_unregister_port(line); | 117 | switch (info->type) { |
118 | case PORT_8250 ... PORT_MAX_8250: | ||
119 | serial8250_unregister_port(info->line); | ||
120 | break; | ||
121 | default: | ||
122 | /* need to add code for these */ | ||
123 | break; | ||
124 | } | ||
125 | kfree(info); | ||
107 | return 0; | 126 | return 0; |
108 | } | 127 | } |
109 | 128 | ||
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 403dac787ebf..9b7a76be36a0 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -1790,8 +1790,8 @@ config FB_IBM_GXT4500 | |||
1790 | adaptor, found on some IBM System P (pSeries) machines. | 1790 | adaptor, found on some IBM System P (pSeries) machines. |
1791 | 1791 | ||
1792 | config FB_PS3 | 1792 | config FB_PS3 |
1793 | bool "PS3 GPU framebuffer driver" | 1793 | tristate "PS3 GPU framebuffer driver" |
1794 | depends on (FB = y) && PS3_PS3AV | 1794 | depends on FB && PS3_PS3AV |
1795 | select FB_SYS_FILLRECT | 1795 | select FB_SYS_FILLRECT |
1796 | select FB_SYS_COPYAREA | 1796 | select FB_SYS_COPYAREA |
1797 | select FB_SYS_IMAGEBLIT | 1797 | select FB_SYS_IMAGEBLIT |
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 9cf92ba5d6e3..08b7ffbbbbd8 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/vmalloc.h> | 27 | #include <linux/vmalloc.h> |
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/console.h> | 30 | #include <linux/console.h> |
32 | #include <linux/ioctl.h> | 31 | #include <linux/ioctl.h> |
33 | #include <linux/notifier.h> | 32 | #include <linux/notifier.h> |
@@ -46,6 +45,9 @@ | |||
46 | #include <asm/ps3fb.h> | 45 | #include <asm/ps3fb.h> |
47 | #include <asm/ps3.h> | 46 | #include <asm/ps3.h> |
48 | 47 | ||
48 | |||
49 | #define DEVICE_NAME "ps3fb" | ||
50 | |||
49 | #ifdef PS3FB_DEBUG | 51 | #ifdef PS3FB_DEBUG |
50 | #define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args) | 52 | #define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args) |
51 | #else | 53 | #else |
@@ -126,7 +128,6 @@ struct gpu_driver_info { | |||
126 | 128 | ||
127 | struct ps3fb_priv { | 129 | struct ps3fb_priv { |
128 | unsigned int irq_no; | 130 | unsigned int irq_no; |
129 | void *dev; | ||
130 | 131 | ||
131 | u64 context_handle, memory_handle; | 132 | u64 context_handle, memory_handle; |
132 | void *xdr_ea; | 133 | void *xdr_ea; |
@@ -171,7 +172,7 @@ static const struct ps3fb_res_table ps3fb_res[] = { | |||
171 | { 0, 0, 0, 0 , 0} }; | 172 | { 0, 0, 0, 0 , 0} }; |
172 | 173 | ||
173 | /* default resolution */ | 174 | /* default resolution */ |
174 | #define GPU_RES_INDEX 0 /* 720 x 480 */ | 175 | #define GPU_RES_INDEX 0 /* 720 x 480 */ |
175 | 176 | ||
176 | static const struct fb_videomode ps3fb_modedb[] = { | 177 | static const struct fb_videomode ps3fb_modedb[] = { |
177 | /* 60 Hz broadcast modes (modes "1" to "5") */ | 178 | /* 60 Hz broadcast modes (modes "1" to "5") */ |
@@ -298,10 +299,9 @@ static const struct fb_videomode ps3fb_modedb[] = { | |||
298 | #define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET) | 299 | #define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET) |
299 | 300 | ||
300 | static int ps3fb_mode; | 301 | static int ps3fb_mode; |
301 | module_param(ps3fb_mode, bool, 0); | 302 | module_param(ps3fb_mode, int, 0); |
302 | |||
303 | static char *mode_option __initdata; | ||
304 | 303 | ||
304 | static char *mode_option __devinitdata; | ||
305 | 305 | ||
306 | static int ps3fb_get_res_table(u32 xres, u32 yres) | 306 | static int ps3fb_get_res_table(u32 xres, u32 yres) |
307 | { | 307 | { |
@@ -681,15 +681,15 @@ int ps3fb_wait_for_vsync(u32 crtc) | |||
681 | 681 | ||
682 | EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync); | 682 | EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync); |
683 | 683 | ||
684 | void ps3fb_flip_ctl(int on) | 684 | void ps3fb_flip_ctl(int on, void *data) |
685 | { | 685 | { |
686 | struct ps3fb_priv *priv = data; | ||
686 | if (on) | 687 | if (on) |
687 | atomic_dec_if_positive(&ps3fb.ext_flip); | 688 | atomic_dec_if_positive(&priv->ext_flip); |
688 | else | 689 | else |
689 | atomic_inc(&ps3fb.ext_flip); | 690 | atomic_inc(&priv->ext_flip); |
690 | } | 691 | } |
691 | 692 | ||
692 | EXPORT_SYMBOL_GPL(ps3fb_flip_ctl); | ||
693 | 693 | ||
694 | /* | 694 | /* |
695 | * ioctl | 695 | * ioctl |
@@ -851,37 +851,9 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) | |||
851 | return IRQ_HANDLED; | 851 | return IRQ_HANDLED; |
852 | } | 852 | } |
853 | 853 | ||
854 | #ifndef MODULE | ||
855 | static int __init ps3fb_setup(char *options) | ||
856 | { | ||
857 | char *this_opt; | ||
858 | int mode = 0; | ||
859 | |||
860 | if (!options || !*options) | ||
861 | return 0; /* no options */ | ||
862 | |||
863 | while ((this_opt = strsep(&options, ",")) != NULL) { | ||
864 | if (!*this_opt) | ||
865 | continue; | ||
866 | if (!strncmp(this_opt, "mode:", 5)) | ||
867 | mode = simple_strtoul(this_opt + 5, NULL, 0); | ||
868 | else | ||
869 | mode_option = this_opt; | ||
870 | } | ||
871 | return mode; | ||
872 | } | ||
873 | #endif /* MODULE */ | ||
874 | |||
875 | /* | ||
876 | * Initialisation | ||
877 | */ | ||
878 | 854 | ||
879 | static void ps3fb_platform_release(struct device *device) | 855 | static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, |
880 | { | 856 | struct ps3_system_bus_device *dev) |
881 | /* This is called when the reference count goes to zero. */ | ||
882 | } | ||
883 | |||
884 | static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) | ||
885 | { | 857 | { |
886 | int error; | 858 | int error; |
887 | 859 | ||
@@ -897,7 +869,6 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) | |||
897 | return -EINVAL; | 869 | return -EINVAL; |
898 | } | 870 | } |
899 | 871 | ||
900 | ps3fb.dev = dev; | ||
901 | error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, | 872 | error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, |
902 | &ps3fb.irq_no); | 873 | &ps3fb.irq_no); |
903 | if (error) { | 874 | if (error) { |
@@ -907,7 +878,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) | |||
907 | } | 878 | } |
908 | 879 | ||
909 | error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, | 880 | error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, |
910 | "ps3fb vsync", ps3fb.dev); | 881 | DEVICE_NAME, dev); |
911 | if (error) { | 882 | if (error) { |
912 | printk(KERN_ERR "%s: request_irq failed %d\n", __func__, | 883 | printk(KERN_ERR "%s: request_irq failed %d\n", __func__, |
913 | error); | 884 | error); |
@@ -966,16 +937,45 @@ static struct fb_ops ps3fb_ops = { | |||
966 | }; | 937 | }; |
967 | 938 | ||
968 | static struct fb_fix_screeninfo ps3fb_fix __initdata = { | 939 | static struct fb_fix_screeninfo ps3fb_fix __initdata = { |
969 | .id = "PS3 FB", | 940 | .id = DEVICE_NAME, |
970 | .type = FB_TYPE_PACKED_PIXELS, | 941 | .type = FB_TYPE_PACKED_PIXELS, |
971 | .visual = FB_VISUAL_TRUECOLOR, | 942 | .visual = FB_VISUAL_TRUECOLOR, |
972 | .accel = FB_ACCEL_NONE, | 943 | .accel = FB_ACCEL_NONE, |
973 | }; | 944 | }; |
974 | 945 | ||
975 | static int __init ps3fb_probe(struct platform_device *dev) | 946 | static int ps3fb_set_sync(void) |
947 | { | ||
948 | int status; | ||
949 | |||
950 | #ifdef HEAD_A | ||
951 | status = lv1_gpu_context_attribute(0x0, | ||
952 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | ||
953 | 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | ||
954 | if (status) { | ||
955 | printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC " | ||
956 | "failed: %d\n", __func__, status); | ||
957 | return -1; | ||
958 | } | ||
959 | #endif | ||
960 | #ifdef HEAD_B | ||
961 | status = lv1_gpu_context_attribute(0x0, | ||
962 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | ||
963 | 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | ||
964 | |||
965 | if (status) { | ||
966 | printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE " | ||
967 | "failed: %d\n", __func__, status); | ||
968 | return -1; | ||
969 | } | ||
970 | #endif | ||
971 | return 0; | ||
972 | } | ||
973 | |||
974 | static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | ||
976 | { | 975 | { |
977 | struct fb_info *info; | 976 | struct fb_info *info; |
978 | int retval = -ENOMEM; | 977 | int retval = -ENOMEM; |
978 | u32 xres, yres; | ||
979 | u64 ddr_lpar = 0; | 979 | u64 ddr_lpar = 0; |
980 | u64 lpar_dma_control = 0; | 980 | u64 lpar_dma_control = 0; |
981 | u64 lpar_driver_info = 0; | 981 | u64 lpar_driver_info = 0; |
@@ -986,6 +986,30 @@ static int __init ps3fb_probe(struct platform_device *dev) | |||
986 | unsigned long offset; | 986 | unsigned long offset; |
987 | struct task_struct *task; | 987 | struct task_struct *task; |
988 | 988 | ||
989 | status = ps3_open_hv_device(dev); | ||
990 | if (status) { | ||
991 | printk(KERN_ERR "%s: ps3_open_hv_device failed\n", __func__); | ||
992 | goto err; | ||
993 | } | ||
994 | |||
995 | if (!ps3fb_mode) | ||
996 | ps3fb_mode = ps3av_get_mode(); | ||
997 | DPRINTK("ps3av_mode:%d\n", ps3fb_mode); | ||
998 | |||
999 | if (ps3fb_mode > 0 && | ||
1000 | !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) { | ||
1001 | ps3fb.res_index = ps3fb_get_res_table(xres, yres); | ||
1002 | DPRINTK("res_index:%d\n", ps3fb.res_index); | ||
1003 | } else | ||
1004 | ps3fb.res_index = GPU_RES_INDEX; | ||
1005 | |||
1006 | atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ | ||
1007 | atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ | ||
1008 | init_waitqueue_head(&ps3fb.wait_vsync); | ||
1009 | ps3fb.num_frames = 1; | ||
1010 | |||
1011 | ps3fb_set_sync(); | ||
1012 | |||
989 | /* get gpu context handle */ | 1013 | /* get gpu context handle */ |
990 | status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0, | 1014 | status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0, |
991 | &ps3fb.memory_handle, &ddr_lpar); | 1015 | &ps3fb.memory_handle, &ddr_lpar); |
@@ -1029,7 +1053,7 @@ static int __init ps3fb_probe(struct platform_device *dev) | |||
1029 | * leakage into userspace | 1053 | * leakage into userspace |
1030 | */ | 1054 | */ |
1031 | memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); | 1055 | memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); |
1032 | info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); | 1056 | info = framebuffer_alloc(sizeof(u32) * 16, &dev->core); |
1033 | if (!info) | 1057 | if (!info) |
1034 | goto err_free_irq; | 1058 | goto err_free_irq; |
1035 | 1059 | ||
@@ -1061,19 +1085,20 @@ static int __init ps3fb_probe(struct platform_device *dev) | |||
1061 | if (retval < 0) | 1085 | if (retval < 0) |
1062 | goto err_fb_dealloc; | 1086 | goto err_fb_dealloc; |
1063 | 1087 | ||
1064 | platform_set_drvdata(dev, info); | 1088 | dev->core.driver_data = info; |
1065 | 1089 | ||
1066 | printk(KERN_INFO | 1090 | printk(KERN_INFO |
1067 | "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n", | 1091 | "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n", |
1068 | info->node, ps3fb_videomemory.size >> 10); | 1092 | info->node, ps3fb_videomemory.size >> 10); |
1069 | 1093 | ||
1070 | task = kthread_run(ps3fbd, info, "ps3fbd"); | 1094 | task = kthread_run(ps3fbd, info, DEVICE_NAME); |
1071 | if (IS_ERR(task)) { | 1095 | if (IS_ERR(task)) { |
1072 | retval = PTR_ERR(task); | 1096 | retval = PTR_ERR(task); |
1073 | goto err_unregister_framebuffer; | 1097 | goto err_unregister_framebuffer; |
1074 | } | 1098 | } |
1075 | 1099 | ||
1076 | ps3fb.task = task; | 1100 | ps3fb.task = task; |
1101 | ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb); | ||
1077 | 1102 | ||
1078 | return 0; | 1103 | return 0; |
1079 | 1104 | ||
@@ -1084,7 +1109,7 @@ err_fb_dealloc: | |||
1084 | err_framebuffer_release: | 1109 | err_framebuffer_release: |
1085 | framebuffer_release(info); | 1110 | framebuffer_release(info); |
1086 | err_free_irq: | 1111 | err_free_irq: |
1087 | free_irq(ps3fb.irq_no, ps3fb.dev); | 1112 | free_irq(ps3fb.irq_no, dev); |
1088 | ps3_irq_plug_destroy(ps3fb.irq_no); | 1113 | ps3_irq_plug_destroy(ps3fb.irq_no); |
1089 | err_iounmap_dinfo: | 1114 | err_iounmap_dinfo: |
1090 | iounmap((u8 __iomem *)ps3fb.dinfo); | 1115 | iounmap((u8 __iomem *)ps3fb.dinfo); |
@@ -1096,26 +1121,30 @@ err: | |||
1096 | return retval; | 1121 | return retval; |
1097 | } | 1122 | } |
1098 | 1123 | ||
1099 | static void ps3fb_shutdown(struct platform_device *dev) | 1124 | static int ps3fb_shutdown(struct ps3_system_bus_device *dev) |
1100 | { | 1125 | { |
1101 | ps3fb_flip_ctl(0); /* flip off */ | 1126 | int status; |
1127 | struct fb_info *info = dev->core.driver_data; | ||
1128 | |||
1129 | DPRINTK(" -> %s:%d\n", __func__, __LINE__); | ||
1130 | |||
1131 | ps3fb_flip_ctl(0, &ps3fb); /* flip off */ | ||
1102 | ps3fb.dinfo->irq.mask = 0; | 1132 | ps3fb.dinfo->irq.mask = 0; |
1103 | free_irq(ps3fb.irq_no, ps3fb.dev); | ||
1104 | ps3_irq_plug_destroy(ps3fb.irq_no); | ||
1105 | iounmap((u8 __iomem *)ps3fb.dinfo); | ||
1106 | } | ||
1107 | 1133 | ||
1108 | void ps3fb_cleanup(void) | 1134 | if (info) { |
1109 | { | 1135 | unregister_framebuffer(info); |
1110 | int status; | 1136 | fb_dealloc_cmap(&info->cmap); |
1137 | framebuffer_release(info); | ||
1138 | } | ||
1111 | 1139 | ||
1140 | ps3av_register_flip_ctl(NULL, NULL); | ||
1112 | if (ps3fb.task) { | 1141 | if (ps3fb.task) { |
1113 | struct task_struct *task = ps3fb.task; | 1142 | struct task_struct *task = ps3fb.task; |
1114 | ps3fb.task = NULL; | 1143 | ps3fb.task = NULL; |
1115 | kthread_stop(task); | 1144 | kthread_stop(task); |
1116 | } | 1145 | } |
1117 | if (ps3fb.irq_no) { | 1146 | if (ps3fb.irq_no) { |
1118 | free_irq(ps3fb.irq_no, ps3fb.dev); | 1147 | free_irq(ps3fb.irq_no, dev); |
1119 | ps3_irq_plug_destroy(ps3fb.irq_no); | 1148 | ps3_irq_plug_destroy(ps3fb.irq_no); |
1120 | } | 1149 | } |
1121 | iounmap((u8 __iomem *)ps3fb.dinfo); | 1150 | iounmap((u8 __iomem *)ps3fb.dinfo); |
@@ -1128,134 +1157,69 @@ void ps3fb_cleanup(void) | |||
1128 | if (status) | 1157 | if (status) |
1129 | DPRINTK("lv1_gpu_memory_free failed: %d\n", status); | 1158 | DPRINTK("lv1_gpu_memory_free failed: %d\n", status); |
1130 | 1159 | ||
1131 | ps3av_dev_close(); | 1160 | ps3_close_hv_device(dev); |
1132 | } | 1161 | DPRINTK(" <- %s:%d\n", __func__, __LINE__); |
1133 | 1162 | ||
1134 | EXPORT_SYMBOL_GPL(ps3fb_cleanup); | ||
1135 | |||
1136 | static int ps3fb_remove(struct platform_device *dev) | ||
1137 | { | ||
1138 | struct fb_info *info = platform_get_drvdata(dev); | ||
1139 | |||
1140 | if (info) { | ||
1141 | unregister_framebuffer(info); | ||
1142 | fb_dealloc_cmap(&info->cmap); | ||
1143 | framebuffer_release(info); | ||
1144 | } | ||
1145 | ps3fb_cleanup(); | ||
1146 | return 0; | 1163 | return 0; |
1147 | } | 1164 | } |
1148 | 1165 | ||
1149 | static struct platform_driver ps3fb_driver = { | 1166 | static struct ps3_system_bus_driver ps3fb_driver = { |
1150 | .probe = ps3fb_probe, | 1167 | .match_id = PS3_MATCH_ID_GRAPHICS, |
1151 | .remove = ps3fb_remove, | 1168 | .core.name = DEVICE_NAME, |
1152 | .shutdown = ps3fb_shutdown, | 1169 | .core.owner = THIS_MODULE, |
1153 | .driver = { .name = "ps3fb" } | 1170 | .probe = ps3fb_probe, |
1154 | }; | 1171 | .remove = ps3fb_shutdown, |
1155 | 1172 | .shutdown = ps3fb_shutdown, | |
1156 | static struct platform_device ps3fb_device = { | ||
1157 | .name = "ps3fb", | ||
1158 | .id = 0, | ||
1159 | .dev = { .release = ps3fb_platform_release } | ||
1160 | }; | 1173 | }; |
1161 | 1174 | ||
1162 | int ps3fb_set_sync(void) | 1175 | static int __init ps3fb_setup(void) |
1163 | { | 1176 | { |
1164 | int status; | 1177 | char *options; |
1165 | 1178 | ||
1166 | #ifdef HEAD_A | 1179 | #ifdef MODULE |
1167 | status = lv1_gpu_context_attribute(0x0, | ||
1168 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | ||
1169 | 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | ||
1170 | if (status) { | ||
1171 | printk(KERN_ERR | ||
1172 | "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n", | ||
1173 | __func__, status); | ||
1174 | return -1; | ||
1175 | } | ||
1176 | #endif | ||
1177 | #ifdef HEAD_B | ||
1178 | status = lv1_gpu_context_attribute(0x0, | ||
1179 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | ||
1180 | 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | ||
1181 | |||
1182 | if (status) { | ||
1183 | printk(KERN_ERR | ||
1184 | "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n", | ||
1185 | __func__, status); | ||
1186 | return -1; | ||
1187 | } | ||
1188 | #endif | ||
1189 | return 0; | 1180 | return 0; |
1190 | } | ||
1191 | |||
1192 | EXPORT_SYMBOL_GPL(ps3fb_set_sync); | ||
1193 | |||
1194 | static int __init ps3fb_init(void) | ||
1195 | { | ||
1196 | int error; | ||
1197 | #ifndef MODULE | ||
1198 | int mode; | ||
1199 | char *option = NULL; | ||
1200 | |||
1201 | if (fb_get_options("ps3fb", &option)) | ||
1202 | goto err; | ||
1203 | #endif | 1181 | #endif |
1204 | 1182 | ||
1205 | if (!ps3fb_videomemory.address) | 1183 | if (fb_get_options(DEVICE_NAME, &options)) |
1206 | goto err; | 1184 | return -ENXIO; |
1207 | |||
1208 | error = ps3av_dev_open(); | ||
1209 | if (error) { | ||
1210 | printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__); | ||
1211 | goto err; | ||
1212 | } | ||
1213 | 1185 | ||
1214 | ps3fb_mode = ps3av_get_mode(); | 1186 | if (!options || !*options) |
1215 | DPRINTK("ps3av_mode:%d\n", ps3fb_mode); | 1187 | return 0; |
1216 | #ifndef MODULE | ||
1217 | mode = ps3fb_setup(option); /* check boot option */ | ||
1218 | if (mode) | ||
1219 | ps3fb_mode = mode; | ||
1220 | #endif | ||
1221 | if (ps3fb_mode > 0) { | ||
1222 | u32 xres, yres; | ||
1223 | ps3av_video_mode2res(ps3fb_mode, &xres, &yres); | ||
1224 | ps3fb.res_index = ps3fb_get_res_table(xres, yres); | ||
1225 | DPRINTK("res_index:%d\n", ps3fb.res_index); | ||
1226 | } else | ||
1227 | ps3fb.res_index = GPU_RES_INDEX; | ||
1228 | 1188 | ||
1229 | atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ | 1189 | while (1) { |
1230 | atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ | 1190 | char *this_opt = strsep(&options, ","); |
1231 | init_waitqueue_head(&ps3fb.wait_vsync); | ||
1232 | ps3fb.num_frames = 1; | ||
1233 | 1191 | ||
1234 | error = platform_driver_register(&ps3fb_driver); | 1192 | if (!this_opt) |
1235 | if (!error) { | 1193 | break; |
1236 | error = platform_device_register(&ps3fb_device); | 1194 | if (!*this_opt) |
1237 | if (error) | 1195 | continue; |
1238 | platform_driver_unregister(&ps3fb_driver); | 1196 | if (!strncmp(this_opt, "mode:", 5)) |
1197 | ps3fb_mode = simple_strtoul(this_opt + 5, NULL, 0); | ||
1198 | else | ||
1199 | mode_option = this_opt; | ||
1239 | } | 1200 | } |
1201 | return 0; | ||
1202 | } | ||
1240 | 1203 | ||
1241 | ps3fb_set_sync(); | 1204 | static int __init ps3fb_init(void) |
1242 | 1205 | { | |
1243 | return error; | 1206 | if (!ps3fb_videomemory.address || ps3fb_setup()) |
1207 | return -ENXIO; | ||
1244 | 1208 | ||
1245 | err: | 1209 | return ps3_system_bus_driver_register(&ps3fb_driver); |
1246 | return -ENXIO; | ||
1247 | } | 1210 | } |
1248 | 1211 | ||
1249 | module_init(ps3fb_init); | ||
1250 | |||
1251 | #ifdef MODULE | ||
1252 | static void __exit ps3fb_exit(void) | 1212 | static void __exit ps3fb_exit(void) |
1253 | { | 1213 | { |
1254 | platform_device_unregister(&ps3fb_device); | 1214 | DPRINTK(" -> %s:%d\n", __func__, __LINE__); |
1255 | platform_driver_unregister(&ps3fb_driver); | 1215 | ps3_system_bus_driver_unregister(&ps3fb_driver); |
1216 | DPRINTK(" <- %s:%d\n", __func__, __LINE__); | ||
1256 | } | 1217 | } |
1257 | 1218 | ||
1219 | module_init(ps3fb_init); | ||
1258 | module_exit(ps3fb_exit); | 1220 | module_exit(ps3fb_exit); |
1259 | 1221 | ||
1260 | MODULE_LICENSE("GPL"); | 1222 | MODULE_LICENSE("GPL"); |
1261 | #endif /* MODULE */ | 1223 | MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver"); |
1224 | MODULE_AUTHOR("Sony Computer Entertainment Inc."); | ||
1225 | MODULE_ALIAS(PS3_MODULE_ALIAS_GRAPHICS); | ||