2017-11-06 20:11:51 +03:00
// SPDX-License-Identifier: GPL-2.0
2013-01-22 03:38:47 +04:00
/*
* Copyright ( C ) 2007 Google , Inc .
* Copyright ( C ) 2012 Intel , Inc .
2017-08-29 16:53:20 +03:00
* Copyright ( C ) 2017 Imagination Technologies Ltd .
2013-01-22 03:38:47 +04:00
*/
# include <linux/console.h>
# include <linux/interrupt.h>
# include <linux/platform_device.h>
# include <linux/tty.h>
# include <linux/tty_flip.h>
# include <linux/slab.h>
# include <linux/io.h>
# include <linux/module.h>
2018-06-20 08:47:28 +03:00
# include <linux/mod_devicetable.h>
2014-05-12 19:57:05 +04:00
# include <linux/goldfish.h>
2017-08-29 16:53:19 +03:00
# include <linux/mm.h>
# include <linux/dma-mapping.h>
2017-08-29 16:53:20 +03:00
# include <linux/serial_core.h>
2013-01-22 03:38:47 +04:00
2017-08-29 16:53:18 +03:00
/* Goldfish tty register's offsets */
# define GOLDFISH_TTY_REG_BYTES_READY 0x04
# define GOLDFISH_TTY_REG_CMD 0x08
# define GOLDFISH_TTY_REG_DATA_PTR 0x10
# define GOLDFISH_TTY_REG_DATA_LEN 0x14
# define GOLDFISH_TTY_REG_DATA_PTR_HIGH 0x18
2017-08-29 16:53:19 +03:00
# define GOLDFISH_TTY_REG_VERSION 0x20
2017-08-29 16:53:18 +03:00
/* Goldfish tty commands */
# define GOLDFISH_TTY_CMD_INT_DISABLE 0
# define GOLDFISH_TTY_CMD_INT_ENABLE 1
# define GOLDFISH_TTY_CMD_WRITE_BUFFER 2
# define GOLDFISH_TTY_CMD_READ_BUFFER 3
2013-01-22 03:38:47 +04:00
struct goldfish_tty {
struct tty_port port ;
spinlock_t lock ;
void __iomem * base ;
u32 irq ;
int opencount ;
struct console console ;
2017-08-29 16:53:19 +03:00
u32 version ;
struct device * dev ;
2013-01-22 03:38:47 +04:00
} ;
static DEFINE_MUTEX ( goldfish_tty_lock ) ;
static struct tty_driver * goldfish_tty_driver ;
static u32 goldfish_tty_line_count = 8 ;
static u32 goldfish_tty_current_line_count ;
static struct goldfish_tty * goldfish_ttys ;
2017-08-29 16:53:19 +03:00
static void do_rw_io ( struct goldfish_tty * qtty ,
unsigned long address ,
unsigned int count ,
int is_write )
2013-01-22 03:38:47 +04:00
{
unsigned long irq_flags ;
void __iomem * base = qtty - > base ;
2017-08-29 16:53:19 +03:00
2013-01-22 03:38:47 +04:00
spin_lock_irqsave ( & qtty - > lock , irq_flags ) ;
2017-08-29 16:53:19 +03:00
gf_write_ptr ( ( void * ) address , base + GOLDFISH_TTY_REG_DATA_PTR ,
2017-08-29 16:53:18 +03:00
base + GOLDFISH_TTY_REG_DATA_PTR_HIGH ) ;
2022-04-06 23:15:20 +03:00
gf_iowrite32 ( count , base + GOLDFISH_TTY_REG_DATA_LEN ) ;
2017-08-29 16:53:19 +03:00
if ( is_write )
2022-04-06 23:15:20 +03:00
gf_iowrite32 ( GOLDFISH_TTY_CMD_WRITE_BUFFER ,
2017-08-29 16:53:19 +03:00
base + GOLDFISH_TTY_REG_CMD ) ;
else
2022-04-06 23:15:20 +03:00
gf_iowrite32 ( GOLDFISH_TTY_CMD_READ_BUFFER ,
2017-08-29 16:53:19 +03:00
base + GOLDFISH_TTY_REG_CMD ) ;
2013-01-22 03:38:47 +04:00
spin_unlock_irqrestore ( & qtty - > lock , irq_flags ) ;
}
2017-08-29 16:53:19 +03:00
static void goldfish_tty_rw ( struct goldfish_tty * qtty ,
unsigned long addr ,
unsigned int count ,
int is_write )
{
dma_addr_t dma_handle ;
enum dma_data_direction dma_dir ;
dma_dir = ( is_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE ) ;
if ( qtty - > version > 0 ) {
/*
* Goldfish TTY for Ranchu platform uses
* physical addresses and DMA for read / write operations
*/
unsigned long addr_end = addr + count ;
while ( addr < addr_end ) {
unsigned long pg_end = ( addr & PAGE_MASK ) + PAGE_SIZE ;
unsigned long next =
pg_end < addr_end ? pg_end : addr_end ;
unsigned long avail = next - addr ;
/*
* Map the buffer ' s virtual address to the DMA address
* so the buffer can be accessed by the device .
*/
dma_handle = dma_map_single ( qtty - > dev , ( void * ) addr ,
avail , dma_dir ) ;
if ( dma_mapping_error ( qtty - > dev , dma_handle ) ) {
dev_err ( qtty - > dev , " tty: DMA mapping error. \n " ) ;
return ;
}
do_rw_io ( qtty , dma_handle , avail , is_write ) ;
/*
* Unmap the previously mapped region after
* the completion of the read / write operation .
*/
dma_unmap_single ( qtty - > dev , dma_handle , avail , dma_dir ) ;
addr + = avail ;
}
} else {
/*
* Old style Goldfish TTY used on the Goldfish platform
* uses virtual addresses .
*/
do_rw_io ( qtty , addr , count , is_write ) ;
}
}
static void goldfish_tty_do_write ( int line , const char * buf ,
unsigned int count )
{
struct goldfish_tty * qtty = & goldfish_ttys [ line ] ;
unsigned long address = ( unsigned long ) ( void * ) buf ;
goldfish_tty_rw ( qtty , address , count , 1 ) ;
}
2013-01-22 03:38:47 +04:00
static irqreturn_t goldfish_tty_interrupt ( int irq , void * dev_id )
{
2016-02-26 22:01:05 +03:00
struct goldfish_tty * qtty = dev_id ;
2013-01-22 03:38:47 +04:00
void __iomem * base = qtty - > base ;
2017-08-29 16:53:19 +03:00
unsigned long address ;
2013-01-22 03:38:47 +04:00
unsigned char * buf ;
u32 count ;
2022-04-06 23:15:20 +03:00
count = gf_ioread32 ( base + GOLDFISH_TTY_REG_BYTES_READY ) ;
2014-05-12 19:57:14 +04:00
if ( count = = 0 )
2013-01-22 03:38:47 +04:00
return IRQ_NONE ;
2013-01-25 19:05:30 +04:00
count = tty_prepare_flip_string ( & qtty - > port , & buf , count ) ;
2017-08-29 16:53:19 +03:00
address = ( unsigned long ) ( void * ) buf ;
goldfish_tty_rw ( qtty , address , count , 0 ) ;
2021-11-22 14:16:46 +03:00
tty_flip_buffer_push ( & qtty - > port ) ;
2013-01-22 03:38:47 +04:00
return IRQ_HANDLED ;
}
static int goldfish_tty_activate ( struct tty_port * port , struct tty_struct * tty )
{
2014-05-12 19:57:14 +04:00
struct goldfish_tty * qtty = container_of ( port , struct goldfish_tty ,
port ) ;
2022-04-06 23:15:20 +03:00
gf_iowrite32 ( GOLDFISH_TTY_CMD_INT_ENABLE , qtty - > base + GOLDFISH_TTY_REG_CMD ) ;
2013-01-22 03:38:47 +04:00
return 0 ;
}
static void goldfish_tty_shutdown ( struct tty_port * port )
{
2014-05-12 19:57:14 +04:00
struct goldfish_tty * qtty = container_of ( port , struct goldfish_tty ,
port ) ;
2022-04-06 23:15:20 +03:00
gf_iowrite32 ( GOLDFISH_TTY_CMD_INT_DISABLE , qtty - > base + GOLDFISH_TTY_REG_CMD ) ;
2013-01-22 03:38:47 +04:00
}
2014-05-12 19:57:14 +04:00
static int goldfish_tty_open ( struct tty_struct * tty , struct file * filp )
2013-01-22 03:38:47 +04:00
{
struct goldfish_tty * qtty = & goldfish_ttys [ tty - > index ] ;
return tty_port_open ( & qtty - > port , tty , filp ) ;
}
2014-05-12 19:57:14 +04:00
static void goldfish_tty_close ( struct tty_struct * tty , struct file * filp )
2013-01-22 03:38:47 +04:00
{
tty_port_close ( tty - > port , tty , filp ) ;
}
static void goldfish_tty_hangup ( struct tty_struct * tty )
{
tty_port_hangup ( tty - > port ) ;
}
2014-05-12 19:57:14 +04:00
static int goldfish_tty_write ( struct tty_struct * tty , const unsigned char * buf ,
int count )
2013-01-22 03:38:47 +04:00
{
goldfish_tty_do_write ( tty - > index , buf , count ) ;
return count ;
}
2021-05-05 12:19:15 +03:00
static unsigned int goldfish_tty_write_room ( struct tty_struct * tty )
2013-01-22 03:38:47 +04:00
{
return 0x10000 ;
}
2021-05-05 12:19:19 +03:00
static unsigned int goldfish_tty_chars_in_buffer ( struct tty_struct * tty )
2013-01-22 03:38:47 +04:00
{
struct goldfish_tty * qtty = & goldfish_ttys [ tty - > index ] ;
void __iomem * base = qtty - > base ;
2022-04-06 23:15:20 +03:00
return gf_ioread32 ( base + GOLDFISH_TTY_REG_BYTES_READY ) ;
2013-01-22 03:38:47 +04:00
}
2014-05-12 19:57:14 +04:00
static void goldfish_tty_console_write ( struct console * co , const char * b ,
unsigned count )
2013-01-22 03:38:47 +04:00
{
goldfish_tty_do_write ( co - > index , b , count ) ;
}
2014-05-12 19:57:14 +04:00
static struct tty_driver * goldfish_tty_console_device ( struct console * c ,
int * index )
2013-01-22 03:38:47 +04:00
{
* index = c - > index ;
return goldfish_tty_driver ;
}
static int goldfish_tty_console_setup ( struct console * co , char * options )
{
2014-10-29 11:43:25 +03:00
if ( ( unsigned ) co - > index > = goldfish_tty_line_count )
2013-01-22 03:38:47 +04:00
return - ENODEV ;
2014-09-28 22:10:17 +04:00
if ( ! goldfish_ttys [ co - > index ] . base )
2013-01-22 03:38:47 +04:00
return - ENODEV ;
return 0 ;
}
2015-12-15 02:53:36 +03:00
static const struct tty_port_operations goldfish_port_ops = {
2013-01-22 03:38:47 +04:00
. activate = goldfish_tty_activate ,
. shutdown = goldfish_tty_shutdown
} ;
2014-05-12 19:57:14 +04:00
static const struct tty_operations goldfish_tty_ops = {
2013-01-22 03:38:47 +04:00
. open = goldfish_tty_open ,
. close = goldfish_tty_close ,
. hangup = goldfish_tty_hangup ,
. write = goldfish_tty_write ,
. write_room = goldfish_tty_write_room ,
. chars_in_buffer = goldfish_tty_chars_in_buffer ,
} ;
static int goldfish_tty_create_driver ( void )
{
int ret ;
struct tty_driver * tty ;
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:03:40 +03:00
goldfish_ttys = kcalloc ( goldfish_tty_line_count ,
sizeof ( * goldfish_ttys ) ,
GFP_KERNEL ) ;
2014-05-12 19:57:14 +04:00
if ( goldfish_ttys = = NULL ) {
2013-01-22 03:38:47 +04:00
ret = - ENOMEM ;
goto err_alloc_goldfish_ttys_failed ;
}
2021-07-23 10:43:13 +03:00
tty = tty_alloc_driver ( goldfish_tty_line_count ,
TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV ) ;
if ( IS_ERR ( tty ) ) {
ret = PTR_ERR ( tty ) ;
goto err_tty_alloc_driver_failed ;
2013-01-22 03:38:47 +04:00
}
tty - > driver_name = " goldfish " ;
tty - > name = " ttyGF " ;
tty - > type = TTY_DRIVER_TYPE_SERIAL ;
tty - > subtype = SERIAL_TYPE_NORMAL ;
tty - > init_termios = tty_std_termios ;
tty_set_operations ( tty , & goldfish_tty_ops ) ;
ret = tty_register_driver ( tty ) ;
2014-05-12 19:57:14 +04:00
if ( ret )
2013-01-22 03:38:47 +04:00
goto err_tty_register_driver_failed ;
goldfish_tty_driver = tty ;
return 0 ;
err_tty_register_driver_failed :
2021-07-23 10:43:16 +03:00
tty_driver_kref_put ( tty ) ;
2021-07-23 10:43:13 +03:00
err_tty_alloc_driver_failed :
2013-01-22 03:38:47 +04:00
kfree ( goldfish_ttys ) ;
goldfish_ttys = NULL ;
err_alloc_goldfish_ttys_failed :
return ret ;
}
static void goldfish_tty_delete_driver ( void )
{
tty_unregister_driver ( goldfish_tty_driver ) ;
2021-07-23 10:43:16 +03:00
tty_driver_kref_put ( goldfish_tty_driver ) ;
2013-01-22 03:38:47 +04:00
goldfish_tty_driver = NULL ;
kfree ( goldfish_ttys ) ;
goldfish_ttys = NULL ;
}
static int goldfish_tty_probe ( struct platform_device * pdev )
{
struct goldfish_tty * qtty ;
2017-08-29 16:53:19 +03:00
int ret = - ENODEV ;
2013-01-22 03:38:47 +04:00
struct resource * r ;
struct device * ttydev ;
void __iomem * base ;
2021-12-24 18:37:53 +03:00
int irq ;
2016-02-26 22:01:05 +03:00
unsigned int line ;
2013-01-22 03:38:47 +04:00
r = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2017-08-29 16:53:19 +03:00
if ( ! r ) {
pr_err ( " goldfish_tty: No MEM resource available! \n " ) ;
return - ENOMEM ;
}
2013-01-22 03:38:47 +04:00
base = ioremap ( r - > start , 0x1000 ) ;
2017-08-29 16:53:19 +03:00
if ( ! base ) {
pr_err ( " goldfish_tty: Unable to ioremap base! \n " ) ;
return - ENOMEM ;
}
2013-01-22 03:38:47 +04:00
2021-12-24 18:37:53 +03:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
ret = irq ;
2013-01-22 03:38:47 +04:00
goto err_unmap ;
2017-08-29 16:53:19 +03:00
}
2013-01-22 03:38:47 +04:00
mutex_lock ( & goldfish_tty_lock ) ;
2016-02-26 22:01:05 +03:00
if ( pdev - > id = = PLATFORM_DEVID_NONE )
line = goldfish_tty_current_line_count ;
else
line = pdev - > id ;
2017-08-29 16:53:19 +03:00
if ( line > = goldfish_tty_line_count ) {
pr_err ( " goldfish_tty: Reached maximum tty number of %d. \n " ,
goldfish_tty_current_line_count ) ;
ret = - ENOMEM ;
goto err_unlock ;
}
2016-02-26 22:01:05 +03:00
2014-05-12 19:57:14 +04:00
if ( goldfish_tty_current_line_count = = 0 ) {
2013-01-22 03:38:47 +04:00
ret = goldfish_tty_create_driver ( ) ;
2014-05-12 19:57:14 +04:00
if ( ret )
2017-08-29 16:53:19 +03:00
goto err_unlock ;
2013-01-22 03:38:47 +04:00
}
goldfish_tty_current_line_count + + ;
2016-02-26 22:01:05 +03:00
qtty = & goldfish_ttys [ line ] ;
2013-01-22 03:38:47 +04:00
spin_lock_init ( & qtty - > lock ) ;
tty_port_init ( & qtty - > port ) ;
qtty - > port . ops = & goldfish_port_ops ;
qtty - > base = base ;
qtty - > irq = irq ;
2017-08-29 16:53:19 +03:00
qtty - > dev = & pdev - > dev ;
/*
* Goldfish TTY device used by the Goldfish emulator
* should identify itself with 0 , forcing the driver
* to use virtual addresses . Goldfish TTY device
* on Ranchu emulator ( qemu2 ) returns 1 here and
* driver will use physical addresses .
*/
2022-04-06 23:15:20 +03:00
qtty - > version = gf_ioread32 ( base + GOLDFISH_TTY_REG_VERSION ) ;
2017-08-29 16:53:19 +03:00
/*
* Goldfish TTY device on Ranchu emulator ( qemu2 )
* will use DMA for read / write IO operations .
*/
if ( qtty - > version > 0 ) {
/*
* Initialize dma_mask to 32 - bits .
*/
if ( ! pdev - > dev . dma_mask )
pdev - > dev . dma_mask = & pdev - > dev . coherent_dma_mask ;
ret = dma_set_mask ( & pdev - > dev , DMA_BIT_MASK ( 32 ) ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " No suitable DMA available. \n " ) ;
goto err_dec_line_count ;
}
}
2013-01-22 03:38:47 +04:00
2022-04-06 23:15:20 +03:00
gf_iowrite32 ( GOLDFISH_TTY_CMD_INT_DISABLE , base + GOLDFISH_TTY_REG_CMD ) ;
2013-01-22 03:38:47 +04:00
2014-05-12 19:57:14 +04:00
ret = request_irq ( irq , goldfish_tty_interrupt , IRQF_SHARED ,
2017-08-29 16:53:19 +03:00
" goldfish_tty " , qtty ) ;
if ( ret ) {
pr_err ( " goldfish_tty: No IRQ available! \n " ) ;
goto err_dec_line_count ;
}
2013-01-22 03:38:47 +04:00
ttydev = tty_port_register_device ( & qtty - > port , goldfish_tty_driver ,
2017-08-29 16:53:19 +03:00
line , & pdev - > dev ) ;
2014-05-12 19:57:14 +04:00
if ( IS_ERR ( ttydev ) ) {
2013-01-22 03:38:47 +04:00
ret = PTR_ERR ( ttydev ) ;
goto err_tty_register_device_failed ;
}
strcpy ( qtty - > console . name , " ttyGF " ) ;
qtty - > console . write = goldfish_tty_console_write ;
qtty - > console . device = goldfish_tty_console_device ;
qtty - > console . setup = goldfish_tty_console_setup ;
qtty - > console . flags = CON_PRINTBUFFER ;
2016-02-26 22:01:05 +03:00
qtty - > console . index = line ;
2013-01-22 03:38:47 +04:00
register_console ( & qtty - > console ) ;
2016-02-26 22:01:05 +03:00
platform_set_drvdata ( pdev , qtty ) ;
2013-01-22 03:38:47 +04:00
mutex_unlock ( & goldfish_tty_lock ) ;
return 0 ;
err_tty_register_device_failed :
2017-01-09 03:26:37 +03:00
free_irq ( irq , qtty ) ;
2017-08-29 16:53:19 +03:00
err_dec_line_count :
2022-03-28 14:58:44 +03:00
tty_port_destroy ( & qtty - > port ) ;
2013-01-22 03:38:47 +04:00
goldfish_tty_current_line_count - - ;
2014-05-12 19:57:14 +04:00
if ( goldfish_tty_current_line_count = = 0 )
2013-01-22 03:38:47 +04:00
goldfish_tty_delete_driver ( ) ;
2017-08-29 16:53:19 +03:00
err_unlock :
2013-01-22 03:38:47 +04:00
mutex_unlock ( & goldfish_tty_lock ) ;
err_unmap :
iounmap ( base ) ;
return ret ;
}
static int goldfish_tty_remove ( struct platform_device * pdev )
{
2016-02-26 22:01:05 +03:00
struct goldfish_tty * qtty = platform_get_drvdata ( pdev ) ;
2013-01-22 03:38:47 +04:00
mutex_lock ( & goldfish_tty_lock ) ;
unregister_console ( & qtty - > console ) ;
2016-02-26 22:01:05 +03:00
tty_unregister_device ( goldfish_tty_driver , qtty - > console . index ) ;
2013-01-22 03:38:47 +04:00
iounmap ( qtty - > base ) ;
2014-09-28 22:10:17 +04:00
qtty - > base = NULL ;
2022-06-09 17:17:04 +03:00
free_irq ( qtty - > irq , qtty ) ;
2022-03-28 14:58:44 +03:00
tty_port_destroy ( & qtty - > port ) ;
2013-01-22 03:38:47 +04:00
goldfish_tty_current_line_count - - ;
2014-05-12 19:57:14 +04:00
if ( goldfish_tty_current_line_count = = 0 )
2013-01-22 03:38:47 +04:00
goldfish_tty_delete_driver ( ) ;
mutex_unlock ( & goldfish_tty_lock ) ;
return 0 ;
}
2017-11-30 11:16:31 +03:00
# ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE
2022-03-03 11:08:31 +03:00
static void gf_early_console_putchar ( struct uart_port * port , unsigned char ch )
2017-08-29 16:53:20 +03:00
{
2022-04-06 23:15:20 +03:00
gf_iowrite32 ( ch , port - > membase ) ;
2017-08-29 16:53:20 +03:00
}
static void gf_early_write ( struct console * con , const char * s , unsigned int n )
{
struct earlycon_device * dev = con - > data ;
uart_console_write ( & dev - > port , s , n , gf_early_console_putchar ) ;
}
static int __init gf_earlycon_setup ( struct earlycon_device * device ,
const char * opt )
{
if ( ! device - > port . membase )
return - ENODEV ;
device - > con - > write = gf_early_write ;
return 0 ;
}
OF_EARLYCON_DECLARE ( early_gf_tty , " google,goldfish-tty " , gf_earlycon_setup ) ;
2017-11-30 11:16:31 +03:00
# endif
2017-08-29 16:53:20 +03:00
2016-02-26 22:00:44 +03:00
static const struct of_device_id goldfish_tty_of_match [ ] = {
{ . compatible = " google,goldfish-tty " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , goldfish_tty_of_match ) ;
2013-01-22 03:38:47 +04:00
static struct platform_driver goldfish_tty_platform_driver = {
. probe = goldfish_tty_probe ,
. remove = goldfish_tty_remove ,
. driver = {
2016-02-26 22:00:44 +03:00
. name = " goldfish_tty " ,
. of_match_table = goldfish_tty_of_match ,
2013-01-22 03:38:47 +04:00
}
} ;
module_platform_driver ( goldfish_tty_platform_driver ) ;
MODULE_LICENSE ( " GPL v2 " ) ;