root/drivers/ps3/ps3-vuart.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_port_priv
  2. _dump_ports_bmp
  3. _dump_port_params
  4. ps3_vuart_get_triggers
  5. ps3_vuart_set_triggers
  6. ps3_vuart_get_rx_bytes_waiting
  7. ps3_vuart_set_interrupt_mask
  8. ps3_vuart_get_interrupt_status
  9. ps3_vuart_enable_interrupt_tx
  10. ps3_vuart_enable_interrupt_rx
  11. ps3_vuart_enable_interrupt_disconnect
  12. ps3_vuart_disable_interrupt_tx
  13. ps3_vuart_disable_interrupt_rx
  14. ps3_vuart_disable_interrupt_disconnect
  15. ps3_vuart_raw_write
  16. ps3_vuart_raw_read
  17. ps3_vuart_clear_rx_bytes
  18. ps3_vuart_write
  19. ps3_vuart_queue_rx_bytes
  20. ps3_vuart_read
  21. ps3_vuart_work
  22. ps3_vuart_read_async
  23. ps3_vuart_cancel_async
  24. ps3_vuart_handle_interrupt_tx
  25. ps3_vuart_handle_interrupt_rx
  26. ps3_vuart_handle_interrupt_disconnect
  27. ps3_vuart_handle_port_interrupt
  28. ps3_vuart_irq_handler
  29. ps3_vuart_bus_interrupt_get
  30. ps3_vuart_bus_interrupt_put
  31. ps3_vuart_probe
  32. ps3_vuart_cleanup
  33. ps3_vuart_remove
  34. ps3_vuart_shutdown
  35. ps3_vuart_bus_init
  36. ps3_vuart_bus_exit
  37. ps3_vuart_port_driver_register
  38. ps3_vuart_port_driver_unregister

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  PS3 virtual uart
   4  *
   5  *  Copyright (C) 2006 Sony Computer Entertainment Inc.
   6  *  Copyright 2006 Sony Corp.
   7  */
   8 
   9 #include <linux/kernel.h>
  10 #include <linux/slab.h>
  11 #include <linux/module.h>
  12 #include <linux/interrupt.h>
  13 #include <linux/workqueue.h>
  14 #include <linux/bitops.h>
  15 #include <asm/ps3.h>
  16 
  17 #include <asm/firmware.h>
  18 #include <asm/lv1call.h>
  19 
  20 #include "vuart.h"
  21 
  22 MODULE_AUTHOR("Sony Corporation");
  23 MODULE_LICENSE("GPL v2");
  24 MODULE_DESCRIPTION("PS3 vuart");
  25 
  26 /**
  27  * vuart - An inter-partition data link service.
  28  *  port 0: PS3 AV Settings.
  29  *  port 2: PS3 System Manager.
  30  *
  31  * The vuart provides a bi-directional byte stream data link between logical
  32  * partitions.  Its primary role is as a communications link between the guest
  33  * OS and the system policy module.  The current HV does not support any
  34  * connections other than those listed.
  35  */
  36 
  37 enum {PORT_COUNT = 3,};
  38 
  39 enum vuart_param {
  40         PARAM_TX_TRIGGER = 0,
  41         PARAM_RX_TRIGGER = 1,
  42         PARAM_INTERRUPT_MASK = 2,
  43         PARAM_RX_BUF_SIZE = 3, /* read only */
  44         PARAM_RX_BYTES = 4, /* read only */
  45         PARAM_TX_BUF_SIZE = 5, /* read only */
  46         PARAM_TX_BYTES = 6, /* read only */
  47         PARAM_INTERRUPT_STATUS = 7, /* read only */
  48 };
  49 
  50 enum vuart_interrupt_bit {
  51         INTERRUPT_BIT_TX = 0,
  52         INTERRUPT_BIT_RX = 1,
  53         INTERRUPT_BIT_DISCONNECT = 2,
  54 };
  55 
  56 enum vuart_interrupt_mask {
  57         INTERRUPT_MASK_TX = 1,
  58         INTERRUPT_MASK_RX = 2,
  59         INTERRUPT_MASK_DISCONNECT = 4,
  60 };
  61 
  62 /**
  63  * struct ps3_vuart_port_priv - private vuart device data.
  64  */
  65 
  66 struct ps3_vuart_port_priv {
  67         u64 interrupt_mask;
  68 
  69         struct {
  70                 spinlock_t lock;
  71                 struct list_head head;
  72         } tx_list;
  73         struct {
  74                 struct ps3_vuart_work work;
  75                 unsigned long bytes_held;
  76                 spinlock_t lock;
  77                 struct list_head head;
  78         } rx_list;
  79         struct ps3_vuart_stats stats;
  80 };
  81 
  82 static struct ps3_vuart_port_priv *to_port_priv(
  83         struct ps3_system_bus_device *dev)
  84 {
  85         BUG_ON(!dev);
  86         BUG_ON(!dev->driver_priv);
  87         return (struct ps3_vuart_port_priv *)dev->driver_priv;
  88 }
  89 
  90 /**
  91  * struct ports_bmp - bitmap indicating ports needing service.
  92  *
  93  * A 256 bit read only bitmap indicating ports needing service.  Do not write
  94  * to these bits.  Must not cross a page boundary.
  95  */
  96 
  97 struct ports_bmp {
  98         u64 status;
  99         u64 unused[3];
 100 } __attribute__((aligned(32)));
 101 
 102 #define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
 103 static void __maybe_unused _dump_ports_bmp(
 104         const struct ports_bmp *bmp, const char *func, int line)
 105 {
 106         pr_debug("%s:%d: ports_bmp: %016llxh\n", func, line, bmp->status);
 107 }
 108 
 109 #define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__)
 110 static void __maybe_unused _dump_port_params(unsigned int port_number,
 111         const char *func, int line)
 112 {
 113 #if defined(DEBUG)
 114         static const char *strings[] = {
 115                 "tx_trigger      ",
 116                 "rx_trigger      ",
 117                 "interrupt_mask  ",
 118                 "rx_buf_size     ",
 119                 "rx_bytes        ",
 120                 "tx_buf_size     ",
 121                 "tx_bytes        ",
 122                 "interrupt_status",
 123         };
 124         int result;
 125         unsigned int i;
 126         u64 value;
 127 
 128         for (i = 0; i < ARRAY_SIZE(strings); i++) {
 129                 result = lv1_get_virtual_uart_param(port_number, i, &value);
 130 
 131                 if (result) {
 132                         pr_debug("%s:%d: port_%u: %s failed: %s\n", func, line,
 133                                 port_number, strings[i], ps3_result(result));
 134                         continue;
 135                 }
 136                 pr_debug("%s:%d: port_%u: %s = %lxh\n",
 137                         func, line, port_number, strings[i], value);
 138         }
 139 #endif
 140 }
 141 
 142 int ps3_vuart_get_triggers(struct ps3_system_bus_device *dev,
 143         struct vuart_triggers *trig)
 144 {
 145         int result;
 146         u64 size;
 147         u64 val;
 148         u64 tx;
 149 
 150         result = lv1_get_virtual_uart_param(dev->port_number,
 151                 PARAM_TX_TRIGGER, &tx);
 152         trig->tx = tx;
 153 
 154         if (result) {
 155                 dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n",
 156                         __func__, __LINE__, ps3_result(result));
 157                 return result;
 158         }
 159 
 160         result = lv1_get_virtual_uart_param(dev->port_number,
 161                 PARAM_RX_BUF_SIZE, &size);
 162 
 163         if (result) {
 164                 dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n",
 165                         __func__, __LINE__, ps3_result(result));
 166                 return result;
 167         }
 168 
 169         result = lv1_get_virtual_uart_param(dev->port_number,
 170                 PARAM_RX_TRIGGER, &val);
 171 
 172         if (result) {
 173                 dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n",
 174                         __func__, __LINE__, ps3_result(result));
 175                 return result;
 176         }
 177 
 178         trig->rx = size - val;
 179 
 180         dev_dbg(&dev->core, "%s:%d: tx %lxh, rx %lxh\n", __func__, __LINE__,
 181                 trig->tx, trig->rx);
 182 
 183         return result;
 184 }
 185 
 186 int ps3_vuart_set_triggers(struct ps3_system_bus_device *dev, unsigned int tx,
 187         unsigned int rx)
 188 {
 189         int result;
 190         u64 size;
 191 
 192         result = lv1_set_virtual_uart_param(dev->port_number,
 193                 PARAM_TX_TRIGGER, tx);
 194 
 195         if (result) {
 196                 dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n",
 197                         __func__, __LINE__, ps3_result(result));
 198                 return result;
 199         }
 200 
 201         result = lv1_get_virtual_uart_param(dev->port_number,
 202                 PARAM_RX_BUF_SIZE, &size);
 203 
 204         if (result) {
 205                 dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n",
 206                         __func__, __LINE__, ps3_result(result));
 207                 return result;
 208         }
 209 
 210         result = lv1_set_virtual_uart_param(dev->port_number,
 211                 PARAM_RX_TRIGGER, size - rx);
 212 
 213         if (result) {
 214                 dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n",
 215                         __func__, __LINE__, ps3_result(result));
 216                 return result;
 217         }
 218 
 219         dev_dbg(&dev->core, "%s:%d: tx %xh, rx %xh\n", __func__, __LINE__,
 220                 tx, rx);
 221 
 222         return result;
 223 }
 224 
 225 static int ps3_vuart_get_rx_bytes_waiting(struct ps3_system_bus_device *dev,
 226         u64 *bytes_waiting)
 227 {
 228         int result;
 229 
 230         result = lv1_get_virtual_uart_param(dev->port_number,
 231                 PARAM_RX_BYTES, bytes_waiting);
 232 
 233         if (result)
 234                 dev_dbg(&dev->core, "%s:%d: rx_bytes failed: %s\n",
 235                         __func__, __LINE__, ps3_result(result));
 236 
 237         dev_dbg(&dev->core, "%s:%d: %llxh\n", __func__, __LINE__,
 238                 *bytes_waiting);
 239         return result;
 240 }
 241 
 242 /**
 243  * ps3_vuart_set_interrupt_mask - Enable/disable the port interrupt sources.
 244  * @dev: The struct ps3_system_bus_device instance.
 245  * @bmp: Logical OR of enum vuart_interrupt_mask values. A zero bit disables.
 246  */
 247 
 248 static int ps3_vuart_set_interrupt_mask(struct ps3_system_bus_device *dev,
 249         unsigned long mask)
 250 {
 251         int result;
 252         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 253 
 254         dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask);
 255 
 256         priv->interrupt_mask = mask;
 257 
 258         result = lv1_set_virtual_uart_param(dev->port_number,
 259                 PARAM_INTERRUPT_MASK, priv->interrupt_mask);
 260 
 261         if (result)
 262                 dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n",
 263                         __func__, __LINE__, ps3_result(result));
 264 
 265         return result;
 266 }
 267 
 268 static int ps3_vuart_get_interrupt_status(struct ps3_system_bus_device *dev,
 269         unsigned long *status)
 270 {
 271         int result;
 272         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 273         u64 tmp;
 274 
 275         result = lv1_get_virtual_uart_param(dev->port_number,
 276                 PARAM_INTERRUPT_STATUS, &tmp);
 277 
 278         if (result)
 279                 dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n",
 280                         __func__, __LINE__, ps3_result(result));
 281 
 282         *status = tmp & priv->interrupt_mask;
 283 
 284         dev_dbg(&dev->core, "%s:%d: m %llxh, s %llxh, m&s %lxh\n",
 285                 __func__, __LINE__, priv->interrupt_mask, tmp, *status);
 286 
 287         return result;
 288 }
 289 
 290 int ps3_vuart_enable_interrupt_tx(struct ps3_system_bus_device *dev)
 291 {
 292         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 293 
 294         return (priv->interrupt_mask & INTERRUPT_MASK_TX) ? 0
 295                 : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask
 296                 | INTERRUPT_MASK_TX);
 297 }
 298 
 299 int ps3_vuart_enable_interrupt_rx(struct ps3_system_bus_device *dev)
 300 {
 301         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 302 
 303         return (priv->interrupt_mask & INTERRUPT_MASK_RX) ? 0
 304                 : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask
 305                 | INTERRUPT_MASK_RX);
 306 }
 307 
 308 int ps3_vuart_enable_interrupt_disconnect(struct ps3_system_bus_device *dev)
 309 {
 310         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 311 
 312         return (priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0
 313                 : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask
 314                 | INTERRUPT_MASK_DISCONNECT);
 315 }
 316 
 317 int ps3_vuart_disable_interrupt_tx(struct ps3_system_bus_device *dev)
 318 {
 319         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 320 
 321         return (priv->interrupt_mask & INTERRUPT_MASK_TX)
 322                 ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask
 323                 & ~INTERRUPT_MASK_TX) : 0;
 324 }
 325 
 326 int ps3_vuart_disable_interrupt_rx(struct ps3_system_bus_device *dev)
 327 {
 328         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 329 
 330         return (priv->interrupt_mask & INTERRUPT_MASK_RX)
 331                 ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask
 332                 & ~INTERRUPT_MASK_RX) : 0;
 333 }
 334 
 335 int ps3_vuart_disable_interrupt_disconnect(struct ps3_system_bus_device *dev)
 336 {
 337         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 338 
 339         return (priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT)
 340                 ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask
 341                 & ~INTERRUPT_MASK_DISCONNECT) : 0;
 342 }
 343 
 344 /**
 345  * ps3_vuart_raw_write - Low level write helper.
 346  * @dev: The struct ps3_system_bus_device instance.
 347  *
 348  * Do not call ps3_vuart_raw_write directly, use ps3_vuart_write.
 349  */
 350 
 351 static int ps3_vuart_raw_write(struct ps3_system_bus_device *dev,
 352         const void *buf, unsigned int bytes, u64 *bytes_written)
 353 {
 354         int result;
 355         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 356 
 357         result = lv1_write_virtual_uart(dev->port_number,
 358                 ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written);
 359 
 360         if (result) {
 361                 dev_dbg(&dev->core, "%s:%d: lv1_write_virtual_uart failed: "
 362                         "%s\n", __func__, __LINE__, ps3_result(result));
 363                 return result;
 364         }
 365 
 366         priv->stats.bytes_written += *bytes_written;
 367 
 368         dev_dbg(&dev->core, "%s:%d: wrote %llxh/%xh=>%lxh\n", __func__, __LINE__,
 369                 *bytes_written, bytes, priv->stats.bytes_written);
 370 
 371         return result;
 372 }
 373 
 374 /**
 375  * ps3_vuart_raw_read - Low level read helper.
 376  * @dev: The struct ps3_system_bus_device instance.
 377  *
 378  * Do not call ps3_vuart_raw_read directly, use ps3_vuart_read.
 379  */
 380 
 381 static int ps3_vuart_raw_read(struct ps3_system_bus_device *dev, void *buf,
 382         unsigned int bytes, u64 *bytes_read)
 383 {
 384         int result;
 385         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 386 
 387         dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes);
 388 
 389         result = lv1_read_virtual_uart(dev->port_number,
 390                 ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read);
 391 
 392         if (result) {
 393                 dev_dbg(&dev->core, "%s:%d: lv1_read_virtual_uart failed: %s\n",
 394                         __func__, __LINE__, ps3_result(result));
 395                 return result;
 396         }
 397 
 398         priv->stats.bytes_read += *bytes_read;
 399 
 400         dev_dbg(&dev->core, "%s:%d: read %llxh/%xh=>%lxh\n", __func__, __LINE__,
 401                 *bytes_read, bytes, priv->stats.bytes_read);
 402 
 403         return result;
 404 }
 405 
 406 /**
 407  * ps3_vuart_clear_rx_bytes - Discard bytes received.
 408  * @dev: The struct ps3_system_bus_device instance.
 409  * @bytes: Max byte count to discard, zero = all pending.
 410  *
 411  * Used to clear pending rx interrupt source.  Will not block.
 412  */
 413 
 414 void ps3_vuart_clear_rx_bytes(struct ps3_system_bus_device *dev,
 415         unsigned int bytes)
 416 {
 417         int result;
 418         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 419         u64 bytes_waiting;
 420         void *tmp;
 421 
 422         result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes_waiting);
 423 
 424         BUG_ON(result);
 425 
 426         bytes = bytes ? min(bytes, (unsigned int)bytes_waiting) : bytes_waiting;
 427 
 428         dev_dbg(&dev->core, "%s:%d: %u\n", __func__, __LINE__, bytes);
 429 
 430         if (!bytes)
 431                 return;
 432 
 433         /* Add some extra space for recently arrived data. */
 434 
 435         bytes += 128;
 436 
 437         tmp = kmalloc(bytes, GFP_KERNEL);
 438 
 439         if (!tmp)
 440                 return;
 441 
 442         ps3_vuart_raw_read(dev, tmp, bytes, &bytes_waiting);
 443 
 444         kfree(tmp);
 445 
 446         /* Don't include these bytes in the stats. */
 447 
 448         priv->stats.bytes_read -= bytes_waiting;
 449 }
 450 EXPORT_SYMBOL_GPL(ps3_vuart_clear_rx_bytes);
 451 
 452 /**
 453  * struct list_buffer - An element for a port device fifo buffer list.
 454  */
 455 
 456 struct list_buffer {
 457         struct list_head link;
 458         const unsigned char *head;
 459         const unsigned char *tail;
 460         unsigned long dbg_number;
 461         unsigned char data[];
 462 };
 463 
 464 /**
 465  * ps3_vuart_write - the entry point for writing data to a port
 466  * @dev: The struct ps3_system_bus_device instance.
 467  *
 468  * If the port is idle on entry as much of the incoming data is written to
 469  * the port as the port will accept.  Otherwise a list buffer is created
 470  * and any remaning incoming data is copied to that buffer.  The buffer is
 471  * then enqueued for transmision via the transmit interrupt.
 472  */
 473 
 474 int ps3_vuart_write(struct ps3_system_bus_device *dev, const void *buf,
 475         unsigned int bytes)
 476 {
 477         static unsigned long dbg_number;
 478         int result;
 479         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 480         unsigned long flags;
 481         struct list_buffer *lb;
 482 
 483         dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
 484                 bytes, bytes);
 485 
 486         spin_lock_irqsave(&priv->tx_list.lock, flags);
 487 
 488         if (list_empty(&priv->tx_list.head)) {
 489                 u64 bytes_written;
 490 
 491                 result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written);
 492 
 493                 spin_unlock_irqrestore(&priv->tx_list.lock, flags);
 494 
 495                 if (result) {
 496                         dev_dbg(&dev->core,
 497                                 "%s:%d: ps3_vuart_raw_write failed\n",
 498                                 __func__, __LINE__);
 499                         return result;
 500                 }
 501 
 502                 if (bytes_written == bytes) {
 503                         dev_dbg(&dev->core, "%s:%d: wrote %xh bytes\n",
 504                                 __func__, __LINE__, bytes);
 505                         return 0;
 506                 }
 507 
 508                 bytes -= bytes_written;
 509                 buf += bytes_written;
 510         } else
 511                 spin_unlock_irqrestore(&priv->tx_list.lock, flags);
 512 
 513         lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL);
 514 
 515         if (!lb)
 516                 return -ENOMEM;
 517 
 518         memcpy(lb->data, buf, bytes);
 519         lb->head = lb->data;
 520         lb->tail = lb->data + bytes;
 521         lb->dbg_number = ++dbg_number;
 522 
 523         spin_lock_irqsave(&priv->tx_list.lock, flags);
 524         list_add_tail(&lb->link, &priv->tx_list.head);
 525         ps3_vuart_enable_interrupt_tx(dev);
 526         spin_unlock_irqrestore(&priv->tx_list.lock, flags);
 527 
 528         dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n",
 529                 __func__, __LINE__, lb->dbg_number, bytes);
 530 
 531         return 0;
 532 }
 533 EXPORT_SYMBOL_GPL(ps3_vuart_write);
 534 
 535 /**
 536  * ps3_vuart_queue_rx_bytes - Queue waiting bytes into the buffer list.
 537  * @dev: The struct ps3_system_bus_device instance.
 538  * @bytes_queued: Number of bytes queued to the buffer list.
 539  *
 540  * Must be called with priv->rx_list.lock held.
 541  */
 542 
 543 static int ps3_vuart_queue_rx_bytes(struct ps3_system_bus_device *dev,
 544         u64 *bytes_queued)
 545 {
 546         static unsigned long dbg_number;
 547         int result;
 548         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 549         struct list_buffer *lb;
 550         u64 bytes;
 551 
 552         *bytes_queued = 0;
 553 
 554         result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes);
 555         BUG_ON(result);
 556 
 557         if (result)
 558                 return -EIO;
 559 
 560         if (!bytes)
 561                 return 0;
 562 
 563         /* Add some extra space for recently arrived data. */
 564 
 565         bytes += 128;
 566 
 567         lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_ATOMIC);
 568 
 569         if (!lb)
 570                 return -ENOMEM;
 571 
 572         ps3_vuart_raw_read(dev, lb->data, bytes, &bytes);
 573 
 574         lb->head = lb->data;
 575         lb->tail = lb->data + bytes;
 576         lb->dbg_number = ++dbg_number;
 577 
 578         list_add_tail(&lb->link, &priv->rx_list.head);
 579         priv->rx_list.bytes_held += bytes;
 580 
 581         dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %llxh bytes\n",
 582                 __func__, __LINE__, lb->dbg_number, bytes);
 583 
 584         *bytes_queued = bytes;
 585 
 586         return 0;
 587 }
 588 
 589 /**
 590  * ps3_vuart_read - The entry point for reading data from a port.
 591  *
 592  * Queue data waiting at the port, and if enough bytes to satisfy the request
 593  * are held in the buffer list those bytes are dequeued and copied to the
 594  * caller's buffer.  Emptied list buffers are retiered.  If the request cannot
 595  * be statified by bytes held in the list buffers -EAGAIN is returned.
 596  */
 597 
 598 int ps3_vuart_read(struct ps3_system_bus_device *dev, void *buf,
 599         unsigned int bytes)
 600 {
 601         int result;
 602         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 603         unsigned long flags;
 604         struct list_buffer *lb, *n;
 605         unsigned long bytes_read;
 606 
 607         dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
 608                 bytes, bytes);
 609 
 610         spin_lock_irqsave(&priv->rx_list.lock, flags);
 611 
 612         /* Queue rx bytes here for polled reads. */
 613 
 614         while (priv->rx_list.bytes_held < bytes) {
 615                 u64 tmp;
 616 
 617                 result = ps3_vuart_queue_rx_bytes(dev, &tmp);
 618                 if (result || !tmp) {
 619                         dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n",
 620                                 __func__, __LINE__,
 621                                 bytes - priv->rx_list.bytes_held);
 622                         spin_unlock_irqrestore(&priv->rx_list.lock, flags);
 623                         return -EAGAIN;
 624                 }
 625         }
 626 
 627         list_for_each_entry_safe(lb, n, &priv->rx_list.head, link) {
 628                 bytes_read = min((unsigned int)(lb->tail - lb->head), bytes);
 629 
 630                 memcpy(buf, lb->head, bytes_read);
 631                 buf += bytes_read;
 632                 bytes -= bytes_read;
 633                 priv->rx_list.bytes_held -= bytes_read;
 634 
 635                 if (bytes_read < lb->tail - lb->head) {
 636                         lb->head += bytes_read;
 637                         dev_dbg(&dev->core, "%s:%d: buf_%lu: dequeued %lxh "
 638                                 "bytes\n", __func__, __LINE__, lb->dbg_number,
 639                                 bytes_read);
 640                         spin_unlock_irqrestore(&priv->rx_list.lock, flags);
 641                         return 0;
 642                 }
 643 
 644                 dev_dbg(&dev->core, "%s:%d: buf_%lu: free, dequeued %lxh "
 645                         "bytes\n", __func__, __LINE__, lb->dbg_number,
 646                         bytes_read);
 647 
 648                 list_del(&lb->link);
 649                 kfree(lb);
 650         }
 651 
 652         spin_unlock_irqrestore(&priv->rx_list.lock, flags);
 653         return 0;
 654 }
 655 EXPORT_SYMBOL_GPL(ps3_vuart_read);
 656 
 657 /**
 658  * ps3_vuart_work - Asynchronous read handler.
 659  */
 660 
 661 static void ps3_vuart_work(struct work_struct *work)
 662 {
 663         struct ps3_system_bus_device *dev =
 664                 ps3_vuart_work_to_system_bus_dev(work);
 665         struct ps3_vuart_port_driver *drv =
 666                 ps3_system_bus_dev_to_vuart_drv(dev);
 667 
 668         BUG_ON(!drv);
 669         drv->work(dev);
 670 }
 671 
 672 int ps3_vuart_read_async(struct ps3_system_bus_device *dev, unsigned int bytes)
 673 {
 674         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 675         unsigned long flags;
 676 
 677         if (priv->rx_list.work.trigger) {
 678                 dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n",
 679                         __func__, __LINE__);
 680                 return -EAGAIN;
 681         }
 682 
 683         BUG_ON(!bytes);
 684 
 685         spin_lock_irqsave(&priv->rx_list.lock, flags);
 686         if (priv->rx_list.bytes_held >= bytes) {
 687                 dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n",
 688                         __func__, __LINE__, bytes);
 689                 schedule_work(&priv->rx_list.work.work);
 690                 spin_unlock_irqrestore(&priv->rx_list.lock, flags);
 691                 return 0;
 692         }
 693 
 694         priv->rx_list.work.trigger = bytes;
 695         spin_unlock_irqrestore(&priv->rx_list.lock, flags);
 696 
 697         dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__,
 698                 __LINE__, bytes, bytes);
 699 
 700         return 0;
 701 }
 702 EXPORT_SYMBOL_GPL(ps3_vuart_read_async);
 703 
 704 void ps3_vuart_cancel_async(struct ps3_system_bus_device *dev)
 705 {
 706         to_port_priv(dev)->rx_list.work.trigger = 0;
 707 }
 708 EXPORT_SYMBOL_GPL(ps3_vuart_cancel_async);
 709 
 710 /**
 711  * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler
 712  *
 713  * Services the transmit interrupt for the port.  Writes as much data from the
 714  * buffer list as the port will accept.  Retires any emptied list buffers and
 715  * adjusts the final list buffer state for a partial write.
 716  */
 717 
 718 static int ps3_vuart_handle_interrupt_tx(struct ps3_system_bus_device *dev)
 719 {
 720         int result = 0;
 721         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 722         unsigned long flags;
 723         struct list_buffer *lb, *n;
 724         unsigned long bytes_total = 0;
 725 
 726         dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
 727 
 728         spin_lock_irqsave(&priv->tx_list.lock, flags);
 729 
 730         list_for_each_entry_safe(lb, n, &priv->tx_list.head, link) {
 731 
 732                 u64 bytes_written;
 733 
 734                 result = ps3_vuart_raw_write(dev, lb->head, lb->tail - lb->head,
 735                         &bytes_written);
 736 
 737                 if (result) {
 738                         dev_dbg(&dev->core,
 739                                 "%s:%d: ps3_vuart_raw_write failed\n",
 740                                 __func__, __LINE__);
 741                         break;
 742                 }
 743 
 744                 bytes_total += bytes_written;
 745 
 746                 if (bytes_written < lb->tail - lb->head) {
 747                         lb->head += bytes_written;
 748                         dev_dbg(&dev->core,
 749                                 "%s:%d cleared buf_%lu, %llxh bytes\n",
 750                                 __func__, __LINE__, lb->dbg_number,
 751                                 bytes_written);
 752                         goto port_full;
 753                 }
 754 
 755                 dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__,
 756                         lb->dbg_number);
 757 
 758                 list_del(&lb->link);
 759                 kfree(lb);
 760         }
 761 
 762         ps3_vuart_disable_interrupt_tx(dev);
 763 port_full:
 764         spin_unlock_irqrestore(&priv->tx_list.lock, flags);
 765         dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n",
 766                 __func__, __LINE__, bytes_total);
 767         return result;
 768 }
 769 
 770 /**
 771  * ps3_vuart_handle_interrupt_rx - third stage receive interrupt handler
 772  *
 773  * Services the receive interrupt for the port.  Creates a list buffer and
 774  * copies all waiting port data to that buffer and enqueues the buffer in the
 775  * buffer list.  Buffer list data is dequeued via ps3_vuart_read.
 776  */
 777 
 778 static int ps3_vuart_handle_interrupt_rx(struct ps3_system_bus_device *dev)
 779 {
 780         int result;
 781         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 782         unsigned long flags;
 783         u64 bytes;
 784 
 785         dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
 786 
 787         spin_lock_irqsave(&priv->rx_list.lock, flags);
 788         result = ps3_vuart_queue_rx_bytes(dev, &bytes);
 789 
 790         if (result) {
 791                 spin_unlock_irqrestore(&priv->rx_list.lock, flags);
 792                 return result;
 793         }
 794 
 795         if (priv->rx_list.work.trigger && priv->rx_list.bytes_held
 796                 >= priv->rx_list.work.trigger) {
 797                 dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n",
 798                         __func__, __LINE__, priv->rx_list.work.trigger);
 799                 priv->rx_list.work.trigger = 0;
 800                 schedule_work(&priv->rx_list.work.work);
 801         }
 802 
 803         spin_unlock_irqrestore(&priv->rx_list.lock, flags);
 804         return result;
 805 }
 806 
 807 static int ps3_vuart_handle_interrupt_disconnect(
 808         struct ps3_system_bus_device *dev)
 809 {
 810         dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
 811         BUG_ON("no support");
 812         return -1;
 813 }
 814 
 815 /**
 816  * ps3_vuart_handle_port_interrupt - second stage interrupt handler
 817  *
 818  * Services any pending interrupt types for the port.  Passes control to the
 819  * third stage type specific interrupt handler.  Returns control to the first
 820  * stage handler after one iteration.
 821  */
 822 
 823 static int ps3_vuart_handle_port_interrupt(struct ps3_system_bus_device *dev)
 824 {
 825         int result;
 826         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
 827         unsigned long status;
 828 
 829         result = ps3_vuart_get_interrupt_status(dev, &status);
 830 
 831         if (result)
 832                 return result;
 833 
 834         dev_dbg(&dev->core, "%s:%d: status: %lxh\n", __func__, __LINE__,
 835                 status);
 836 
 837         if (status & INTERRUPT_MASK_DISCONNECT) {
 838                 priv->stats.disconnect_interrupts++;
 839                 result = ps3_vuart_handle_interrupt_disconnect(dev);
 840                 if (result)
 841                         ps3_vuart_disable_interrupt_disconnect(dev);
 842         }
 843 
 844         if (status & INTERRUPT_MASK_TX) {
 845                 priv->stats.tx_interrupts++;
 846                 result = ps3_vuart_handle_interrupt_tx(dev);
 847                 if (result)
 848                         ps3_vuart_disable_interrupt_tx(dev);
 849         }
 850 
 851         if (status & INTERRUPT_MASK_RX) {
 852                 priv->stats.rx_interrupts++;
 853                 result = ps3_vuart_handle_interrupt_rx(dev);
 854                 if (result)
 855                         ps3_vuart_disable_interrupt_rx(dev);
 856         }
 857 
 858         return 0;
 859 }
 860 
 861 struct vuart_bus_priv {
 862         struct ports_bmp *bmp;
 863         unsigned int virq;
 864         struct mutex probe_mutex;
 865         int use_count;
 866         struct ps3_system_bus_device *devices[PORT_COUNT];
 867 } static vuart_bus_priv;
 868 
 869 /**
 870  * ps3_vuart_irq_handler - first stage interrupt handler
 871  *
 872  * Loops finding any interrupting port and its associated instance data.
 873  * Passes control to the second stage port specific interrupt handler.  Loops
 874  * until all outstanding interrupts are serviced.
 875  */
 876 
 877 static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private)
 878 {
 879         struct vuart_bus_priv *bus_priv = _private;
 880 
 881         BUG_ON(!bus_priv);
 882 
 883         while (1) {
 884                 unsigned int port;
 885 
 886                 dump_ports_bmp(bus_priv->bmp);
 887 
 888                 port = (BITS_PER_LONG - 1) - __ilog2(bus_priv->bmp->status);
 889 
 890                 if (port == BITS_PER_LONG)
 891                         break;
 892 
 893                 BUG_ON(port >= PORT_COUNT);
 894                 BUG_ON(!bus_priv->devices[port]);
 895 
 896                 ps3_vuart_handle_port_interrupt(bus_priv->devices[port]);
 897         }
 898 
 899         return IRQ_HANDLED;
 900 }
 901 
 902 static int ps3_vuart_bus_interrupt_get(void)
 903 {
 904         int result;
 905 
 906         pr_debug(" -> %s:%d\n", __func__, __LINE__);
 907 
 908         vuart_bus_priv.use_count++;
 909 
 910         BUG_ON(vuart_bus_priv.use_count > 2);
 911 
 912         if (vuart_bus_priv.use_count != 1)
 913                 return 0;
 914 
 915         BUG_ON(vuart_bus_priv.bmp);
 916 
 917         vuart_bus_priv.bmp = kzalloc(sizeof(struct ports_bmp), GFP_KERNEL);
 918 
 919         if (!vuart_bus_priv.bmp) {
 920                 pr_debug("%s:%d: kzalloc failed.\n", __func__, __LINE__);
 921                 result = -ENOMEM;
 922                 goto fail_bmp_malloc;
 923         }
 924 
 925         result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY, vuart_bus_priv.bmp,
 926                 &vuart_bus_priv.virq);
 927 
 928         if (result) {
 929                 pr_debug("%s:%d: ps3_vuart_irq_setup failed (%d)\n",
 930                         __func__, __LINE__, result);
 931                 result = -EPERM;
 932                 goto fail_alloc_irq;
 933         }
 934 
 935         result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler,
 936                 0, "vuart", &vuart_bus_priv);
 937 
 938         if (result) {
 939                 pr_debug("%s:%d: request_irq failed (%d)\n",
 940                         __func__, __LINE__, result);
 941                 goto fail_request_irq;
 942         }
 943 
 944         pr_debug(" <- %s:%d: ok\n", __func__, __LINE__);
 945         return result;
 946 
 947 fail_request_irq:
 948         ps3_vuart_irq_destroy(vuart_bus_priv.virq);
 949         vuart_bus_priv.virq = 0;
 950 fail_alloc_irq:
 951         kfree(vuart_bus_priv.bmp);
 952         vuart_bus_priv.bmp = NULL;
 953 fail_bmp_malloc:
 954         vuart_bus_priv.use_count--;
 955         pr_debug(" <- %s:%d: failed\n", __func__, __LINE__);
 956         return result;
 957 }
 958 
 959 static int ps3_vuart_bus_interrupt_put(void)
 960 {
 961         pr_debug(" -> %s:%d\n", __func__, __LINE__);
 962 
 963         vuart_bus_priv.use_count--;
 964 
 965         BUG_ON(vuart_bus_priv.use_count < 0);
 966 
 967         if (vuart_bus_priv.use_count != 0)
 968                 return 0;
 969 
 970         free_irq(vuart_bus_priv.virq, &vuart_bus_priv);
 971 
 972         ps3_vuart_irq_destroy(vuart_bus_priv.virq);
 973         vuart_bus_priv.virq = 0;
 974 
 975         kfree(vuart_bus_priv.bmp);
 976         vuart_bus_priv.bmp = NULL;
 977 
 978         pr_debug(" <- %s:%d\n", __func__, __LINE__);
 979         return 0;
 980 }
 981 
 982 static int ps3_vuart_probe(struct ps3_system_bus_device *dev)
 983 {
 984         int result;
 985         struct ps3_vuart_port_driver *drv;
 986         struct ps3_vuart_port_priv *priv = NULL;
 987 
 988         dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
 989 
 990         drv = ps3_system_bus_dev_to_vuart_drv(dev);
 991         BUG_ON(!drv);
 992 
 993         dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__,
 994                 drv->core.core.name);
 995 
 996         if (dev->port_number >= PORT_COUNT) {
 997                 BUG();
 998                 return -EINVAL;
 999         }
1000 
1001         mutex_lock(&vuart_bus_priv.probe_mutex);
1002 
1003         result = ps3_vuart_bus_interrupt_get();
1004 
1005         if (result)
1006                 goto fail_setup_interrupt;
1007 
1008         if (vuart_bus_priv.devices[dev->port_number]) {
1009                 dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__,
1010                         __LINE__, dev->port_number);
1011                 result = -EBUSY;
1012                 goto fail_busy;
1013         }
1014 
1015         vuart_bus_priv.devices[dev->port_number] = dev;
1016 
1017         /* Setup dev->driver_priv. */
1018 
1019         dev->driver_priv = kzalloc(sizeof(struct ps3_vuart_port_priv),
1020                 GFP_KERNEL);
1021 
1022         if (!dev->driver_priv) {
1023                 result = -ENOMEM;
1024                 goto fail_dev_malloc;
1025         }
1026 
1027         priv = to_port_priv(dev);
1028 
1029         INIT_LIST_HEAD(&priv->tx_list.head);
1030         spin_lock_init(&priv->tx_list.lock);
1031 
1032         INIT_LIST_HEAD(&priv->rx_list.head);
1033         spin_lock_init(&priv->rx_list.lock);
1034 
1035         INIT_WORK(&priv->rx_list.work.work, ps3_vuart_work);
1036         priv->rx_list.work.trigger = 0;
1037         priv->rx_list.work.dev = dev;
1038 
1039         /* clear stale pending interrupts */
1040 
1041         ps3_vuart_clear_rx_bytes(dev, 0);
1042 
1043         ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX);
1044 
1045         ps3_vuart_set_triggers(dev, 1, 1);
1046 
1047         if (drv->probe)
1048                 result = drv->probe(dev);
1049         else {
1050                 result = 0;
1051                 dev_info(&dev->core, "%s:%d: no probe method\n", __func__,
1052                         __LINE__);
1053         }
1054 
1055         if (result) {
1056                 dev_dbg(&dev->core, "%s:%d: drv->probe failed\n",
1057                         __func__, __LINE__);
1058                 goto fail_probe;
1059         }
1060 
1061         mutex_unlock(&vuart_bus_priv.probe_mutex);
1062 
1063         return result;
1064 
1065 fail_probe:
1066         ps3_vuart_set_interrupt_mask(dev, 0);
1067         kfree(dev->driver_priv);
1068         dev->driver_priv = NULL;
1069 fail_dev_malloc:
1070         vuart_bus_priv.devices[dev->port_number] = NULL;
1071 fail_busy:
1072         ps3_vuart_bus_interrupt_put();
1073 fail_setup_interrupt:
1074         mutex_unlock(&vuart_bus_priv.probe_mutex);
1075         dev_dbg(&dev->core, "%s:%d: failed\n", __func__, __LINE__);
1076         return result;
1077 }
1078 
1079 /**
1080  * ps3_vuart_cleanup - common cleanup helper.
1081  * @dev: The struct ps3_system_bus_device instance.
1082  *
1083  * Cleans interrupts and HV resources.  Must be called with
1084  * vuart_bus_priv.probe_mutex held.  Used by ps3_vuart_remove and
1085  * ps3_vuart_shutdown.  After this call, polled reading will still work.
1086  */
1087 
1088 static int ps3_vuart_cleanup(struct ps3_system_bus_device *dev)
1089 {
1090         dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
1091 
1092         ps3_vuart_cancel_async(dev);
1093         ps3_vuart_set_interrupt_mask(dev, 0);
1094         ps3_vuart_bus_interrupt_put();
1095         return 0;
1096 }
1097 
1098 /**
1099  * ps3_vuart_remove - Completely clean the device instance.
1100  * @dev: The struct ps3_system_bus_device instance.
1101  *
1102  * Cleans all memory, interrupts and HV resources.  After this call the
1103  * device can no longer be used.
1104  */
1105 
1106 static int ps3_vuart_remove(struct ps3_system_bus_device *dev)
1107 {
1108         struct ps3_vuart_port_priv *priv = to_port_priv(dev);
1109         struct ps3_vuart_port_driver *drv;
1110 
1111         BUG_ON(!dev);
1112 
1113         mutex_lock(&vuart_bus_priv.probe_mutex);
1114 
1115         dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,
1116                 dev->match_id);
1117 
1118         if (!dev->core.driver) {
1119                 dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,
1120                         __LINE__);
1121                 mutex_unlock(&vuart_bus_priv.probe_mutex);
1122                 return 0;
1123         }
1124 
1125         drv = ps3_system_bus_dev_to_vuart_drv(dev);
1126 
1127         BUG_ON(!drv);
1128 
1129         if (drv->remove) {
1130                 drv->remove(dev);
1131         } else {
1132                 dev_dbg(&dev->core, "%s:%d: no remove method\n", __func__,
1133                 __LINE__);
1134                 BUG();
1135         }
1136 
1137         ps3_vuart_cleanup(dev);
1138 
1139         vuart_bus_priv.devices[dev->port_number] = NULL;
1140         kfree(priv);
1141         priv = NULL;
1142 
1143         dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
1144         mutex_unlock(&vuart_bus_priv.probe_mutex);
1145         return 0;
1146 }
1147 
1148 /**
1149  * ps3_vuart_shutdown - Cleans interrupts and HV resources.
1150  * @dev: The struct ps3_system_bus_device instance.
1151  *
1152  * Cleans interrupts and HV resources.  After this call the
1153  * device can still be used in polling mode.  This behavior required
1154  * by sys-manager to be able to complete the device power operation
1155  * sequence.
1156  */
1157 
1158 static int ps3_vuart_shutdown(struct ps3_system_bus_device *dev)
1159 {
1160         struct ps3_vuart_port_driver *drv;
1161 
1162         BUG_ON(!dev);
1163 
1164         mutex_lock(&vuart_bus_priv.probe_mutex);
1165 
1166         dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,
1167                 dev->match_id);
1168 
1169         if (!dev->core.driver) {
1170                 dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,
1171                         __LINE__);
1172                 mutex_unlock(&vuart_bus_priv.probe_mutex);
1173                 return 0;
1174         }
1175 
1176         drv = ps3_system_bus_dev_to_vuart_drv(dev);
1177 
1178         BUG_ON(!drv);
1179 
1180         if (drv->shutdown)
1181                 drv->shutdown(dev);
1182         else if (drv->remove) {
1183                 dev_dbg(&dev->core, "%s:%d: no shutdown, calling remove\n",
1184                         __func__, __LINE__);
1185                 drv->remove(dev);
1186         } else {
1187                 dev_dbg(&dev->core, "%s:%d: no shutdown method\n", __func__,
1188                         __LINE__);
1189                 BUG();
1190         }
1191 
1192         ps3_vuart_cleanup(dev);
1193 
1194         dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
1195 
1196         mutex_unlock(&vuart_bus_priv.probe_mutex);
1197         return 0;
1198 }
1199 
1200 static int __init ps3_vuart_bus_init(void)
1201 {
1202         pr_debug("%s:%d:\n", __func__, __LINE__);
1203 
1204         if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
1205                 return -ENODEV;
1206 
1207         mutex_init(&vuart_bus_priv.probe_mutex);
1208 
1209         return 0;
1210 }
1211 
1212 static void __exit ps3_vuart_bus_exit(void)
1213 {
1214         pr_debug("%s:%d:\n", __func__, __LINE__);
1215 }
1216 
1217 core_initcall(ps3_vuart_bus_init);
1218 module_exit(ps3_vuart_bus_exit);
1219 
1220 /**
1221  * ps3_vuart_port_driver_register - Add a vuart port device driver.
1222  */
1223 
1224 int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv)
1225 {
1226         int result;
1227 
1228         pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.core.name);
1229 
1230         BUG_ON(!drv->core.match_id);
1231         BUG_ON(!drv->core.core.name);
1232 
1233         drv->core.probe = ps3_vuart_probe;
1234         drv->core.remove = ps3_vuart_remove;
1235         drv->core.shutdown = ps3_vuart_shutdown;
1236 
1237         result = ps3_system_bus_driver_register(&drv->core);
1238         return result;
1239 }
1240 EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register);
1241 
1242 /**
1243  * ps3_vuart_port_driver_unregister - Remove a vuart port device driver.
1244  */
1245 
1246 void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv)
1247 {
1248         pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.core.name);
1249         ps3_system_bus_driver_unregister(&drv->core);
1250 }
1251 EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_unregister);

/* [<][>][^][v][top][bottom][index][help] */