diff options
Diffstat (limited to 'drivers/ps3')
| -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 |
8 files changed, 1293 insertions, 683 deletions
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 |
