?? device-init.c
字號:
/* * PS3 device registration routines. * * Copyright (C) 2007 Sony Computer Entertainment Inc. * Copyright 2007 Sony Corp. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/delay.h>#include <linux/freezer.h>#include <linux/kernel.h>#include <linux/kthread.h>#include <linux/init.h>#include <asm/firmware.h>#include <asm/lv1call.h>#include <asm/ps3stor.h>#include "platform.h"/** * ps3_setup_gelic_device - Setup and register a gelic device instance. * * Allocates memory for a struct ps3_system_bus_device instance, initialises the * structure members, and registers the device instance with the system bus. */static int __init ps3_setup_gelic_device( const struct ps3_repository_device *repo){ int result; struct layout { struct ps3_system_bus_device dev; struct ps3_dma_region d_region; } *p; pr_debug(" -> %s:%d\n", __func__, __LINE__); BUG_ON(repo->bus_type != PS3_BUS_TYPE_SB); BUG_ON(repo->dev_type != PS3_DEV_TYPE_SB_GELIC); p = kzalloc(sizeof(struct layout), GFP_KERNEL); if (!p) { result = -ENOMEM; goto fail_malloc; } p->dev.match_id = PS3_MATCH_ID_GELIC; p->dev.dev_type = PS3_DEVICE_TYPE_SB; p->dev.bus_id = repo->bus_id; p->dev.dev_id = repo->dev_id; p->dev.d_region = &p->d_region; result = ps3_repository_find_interrupt(repo, PS3_INTERRUPT_TYPE_EVENT_PORT, &p->dev.interrupt_id); if (result) { pr_debug("%s:%d ps3_repository_find_interrupt failed\n", __func__, __LINE__); goto fail_find_interrupt; } BUG_ON(p->dev.interrupt_id != 0); result = ps3_dma_region_init(&p->dev, p->dev.d_region, PS3_DMA_64K, PS3_DMA_OTHER, NULL, 0); if (result) { pr_debug("%s:%d ps3_dma_region_init failed\n", __func__, __LINE__); goto fail_dma_init; } result = ps3_system_bus_device_register(&p->dev); if (result) { pr_debug("%s:%d ps3_system_bus_device_register failed\n", __func__, __LINE__); goto fail_device_register; } pr_debug(" <- %s:%d\n", __func__, __LINE__); return result;fail_device_register:fail_dma_init:fail_find_interrupt: kfree(p);fail_malloc: pr_debug(" <- %s:%d: fail.\n", __func__, __LINE__); return result;}static int __init_refok ps3_setup_uhc_device( const struct ps3_repository_device *repo, enum ps3_match_id match_id, enum ps3_interrupt_type interrupt_type, enum ps3_reg_type reg_type){ int result; struct layout { struct ps3_system_bus_device dev; struct ps3_dma_region d_region; struct ps3_mmio_region m_region; } *p; u64 bus_addr; u64 len; pr_debug(" -> %s:%d\n", __func__, __LINE__); BUG_ON(repo->bus_type != PS3_BUS_TYPE_SB); BUG_ON(repo->dev_type != PS3_DEV_TYPE_SB_USB); p = kzalloc(sizeof(struct layout), GFP_KERNEL); if (!p) { result = -ENOMEM; goto fail_malloc; } p->dev.match_id = match_id; p->dev.dev_type = PS3_DEVICE_TYPE_SB; p->dev.bus_id = repo->bus_id; p->dev.dev_id = repo->dev_id; p->dev.d_region = &p->d_region; p->dev.m_region = &p->m_region; result = ps3_repository_find_interrupt(repo, interrupt_type, &p->dev.interrupt_id); if (result) { pr_debug("%s:%d ps3_repository_find_interrupt failed\n", __func__, __LINE__); goto fail_find_interrupt; } result = ps3_repository_find_reg(repo, reg_type, &bus_addr, &len); if (result) { pr_debug("%s:%d ps3_repository_find_reg failed\n", __func__, __LINE__); goto fail_find_reg; } result = ps3_dma_region_init(&p->dev, p->dev.d_region, PS3_DMA_64K, PS3_DMA_INTERNAL, NULL, 0); if (result) { pr_debug("%s:%d ps3_dma_region_init failed\n", __func__, __LINE__); goto fail_dma_init; } result = ps3_mmio_region_init(&p->dev, p->dev.m_region, bus_addr, len, PS3_MMIO_4K); if (result) { pr_debug("%s:%d ps3_mmio_region_init failed\n", __func__, __LINE__); goto fail_mmio_init; } result = ps3_system_bus_device_register(&p->dev); if (result) { pr_debug("%s:%d ps3_system_bus_device_register failed\n", __func__, __LINE__); goto fail_device_register; } pr_debug(" <- %s:%d\n", __func__, __LINE__); return result;fail_device_register:fail_mmio_init:fail_dma_init:fail_find_reg:fail_find_interrupt: kfree(p);fail_malloc: pr_debug(" <- %s:%d: fail.\n", __func__, __LINE__); return result;}static int __init ps3_setup_ehci_device( const struct ps3_repository_device *repo){ return ps3_setup_uhc_device(repo, PS3_MATCH_ID_EHCI, PS3_INTERRUPT_TYPE_SB_EHCI, PS3_REG_TYPE_SB_EHCI);}static int __init ps3_setup_ohci_device( const struct ps3_repository_device *repo){ return ps3_setup_uhc_device(repo, PS3_MATCH_ID_OHCI, PS3_INTERRUPT_TYPE_SB_OHCI, PS3_REG_TYPE_SB_OHCI);}static int __init ps3_setup_vuart_device(enum ps3_match_id match_id, unsigned int port_number){ int result; struct layout { struct ps3_system_bus_device dev; } *p; pr_debug(" -> %s:%d: match_id %u, port %u\n", __func__, __LINE__, match_id, port_number); p = kzalloc(sizeof(struct layout), GFP_KERNEL); if (!p) return -ENOMEM; p->dev.match_id = match_id; p->dev.dev_type = PS3_DEVICE_TYPE_VUART; p->dev.port_number = port_number; result = ps3_system_bus_device_register(&p->dev); if (result) pr_debug("%s:%d ps3_system_bus_device_register failed\n", __func__, __LINE__); pr_debug(" <- %s:%d\n", __func__, __LINE__); return result;}static int ps3stor_wait_for_completion(u64 dev_id, u64 tag, unsigned int timeout){ int result = -1; unsigned int retries = 0; u64 status; for (retries = 0; retries < timeout; retries++) { result = lv1_storage_check_async_status(dev_id, tag, &status); if (!result) break; msleep(1); } if (result) pr_debug("%s:%u: check_async_status: %s, status %lx\n", __func__, __LINE__, ps3_result(result), status); return result;}/** * ps3_storage_wait_for_device - Wait for a storage device to become ready. * @repo: The repository device to wait for. * * Uses the hypervisor's storage device notification mechanism to wait until * a storage device is ready. The device notification mechanism uses a * psuedo device (id = -1) to asynchronously notify the guest when storage * devices become ready. The notification device has a block size of 512 * bytes. */static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo){ int error = -ENODEV; int result; const u64 notification_dev_id = (u64)-1LL; const unsigned int timeout = HZ; u64 lpar; u64 tag; void *buf; enum ps3_notify_type { notify_device_ready = 0, notify_region_probe = 1, notify_region_update = 2, }; struct { u64 operation_code; /* must be zero */ u64 event_mask; /* OR of 1UL << enum ps3_notify_type */ } *notify_cmd; struct { u64 event_type; /* enum ps3_notify_type */ u64 bus_id; u64 dev_id; u64 dev_type; u64 dev_port; } *notify_event; pr_debug(" -> %s:%u: (%u:%u:%u)\n", __func__, __LINE__, repo->bus_id, repo->dev_id, repo->dev_type); buf = kzalloc(512, GFP_KERNEL); if (!buf) return -ENOMEM; lpar = ps3_mm_phys_to_lpar(__pa(buf)); notify_cmd = buf; notify_event = buf; result = lv1_open_device(repo->bus_id, notification_dev_id, 0); if (result) { printk(KERN_ERR "%s:%u: lv1_open_device %s\n", __func__, __LINE__, ps3_result(result)); goto fail_free; } /* Setup and write the request for device notification. */ notify_cmd->operation_code = 0; /* must be zero */ notify_cmd->event_mask = 1UL << notify_region_probe; result = lv1_storage_write(notification_dev_id, 0, 0, 1, 0, lpar, &tag); if (result) { printk(KERN_ERR "%s:%u: write failed %s\n", __func__, __LINE__, ps3_result(result)); goto fail_close; } /* Wait for the write completion */ result = ps3stor_wait_for_completion(notification_dev_id, tag, timeout); if (result) { printk(KERN_ERR "%s:%u: write not completed %s\n", __func__, __LINE__, ps3_result(result)); goto fail_close; } /* Loop here processing the requested notification events. */ while (1) { memset(notify_event, 0, sizeof(*notify_event)); result = lv1_storage_read(notification_dev_id, 0, 0, 1, 0, lpar, &tag); if (result) { printk(KERN_ERR "%s:%u: write failed %s\n", __func__, __LINE__, ps3_result(result)); break; } result = ps3stor_wait_for_completion(notification_dev_id, tag, timeout); if (result) { printk(KERN_ERR "%s:%u: read not completed %s\n", __func__, __LINE__, ps3_result(result)); break; } pr_debug("%s:%d: notify event (%u:%u:%u): event_type 0x%lx, " "port %lu\n", __func__, __LINE__, repo->bus_index, repo->dev_index, repo->dev_type, notify_event->event_type, notify_event->dev_port); if (notify_event->event_type != notify_region_probe || notify_event->bus_id != repo->bus_id) { pr_debug("%s:%u: bad notify_event: event %lu, " "dev_id %lu, dev_type %lu\n", __func__, __LINE__, notify_event->event_type, notify_event->dev_id, notify_event->dev_type); break; } if (notify_event->dev_id == repo->dev_id && notify_event->dev_type == repo->dev_type) { pr_debug("%s:%u: device ready (%u:%u:%u)\n", __func__, __LINE__, repo->bus_index, repo->dev_index, repo->dev_type); error = 0; break; } if (notify_event->dev_id == repo->dev_id && notify_event->dev_type == PS3_DEV_TYPE_NOACCESS) { pr_debug("%s:%u: no access: dev_id %u\n", __func__, __LINE__, repo->dev_id); break; } }fail_close: lv1_close_device(repo->bus_id, notification_dev_id);fail_free: kfree(buf); pr_debug(" <- %s:%u\n", __func__, __LINE__); return error;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -