cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

parport_amiga.c (6242B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* Low-level parallel port routines for the Amiga built-in port
      3 *
      4 * Author: Joerg Dorchain <joerg@dorchain.net>
      5 *
      6 * This is a complete rewrite of the code, but based heaviy upon the old
      7 * lp_intern. code.
      8 *
      9 * The built-in Amiga parallel port provides one port at a fixed address
     10 * with 8 bidirectional data lines (D0 - D7) and 3 bidirectional status
     11 * lines (BUSY, POUT, SEL), 1 output control line /STROBE (raised automatically
     12 * in hardware when the data register is accessed), and 1 input control line
     13 * /ACK, able to cause an interrupt, but both not directly settable by
     14 * software.
     15 */
     16
     17#include <linux/module.h>
     18#include <linux/init.h>
     19#include <linux/parport.h>
     20#include <linux/ioport.h>
     21#include <linux/interrupt.h>
     22#include <linux/platform_device.h>
     23
     24#include <asm/setup.h>
     25#include <asm/amigahw.h>
     26#include <asm/irq.h>
     27#include <asm/io.h>
     28#include <asm/amigaints.h>
     29
     30#undef DEBUG
     31
     32static void amiga_write_data(struct parport *p, unsigned char data)
     33{
     34	pr_debug("write_data %c\n", data);
     35	/* Triggers also /STROBE. This behavior cannot be changed */
     36	ciaa.prb = data;
     37	mb();
     38}
     39
     40static unsigned char amiga_read_data(struct parport *p)
     41{
     42	/* Triggers also /STROBE. This behavior cannot be changed */
     43	return ciaa.prb;
     44}
     45
     46static unsigned char control_amiga_to_pc(unsigned char control)
     47{
     48	return PARPORT_CONTROL_SELECT |
     49	      PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE;
     50	/* fake value: interrupt enable, select in, no reset,
     51	no autolf, no strobe - seems to be closest the wiring diagram */
     52}
     53
     54static void amiga_write_control(struct parport *p, unsigned char control)
     55{
     56	pr_debug("write_control %02x\n", control);
     57	/* No implementation possible */
     58}
     59	
     60static unsigned char amiga_read_control( struct parport *p)
     61{
     62	pr_debug("read_control\n");
     63	return control_amiga_to_pc(0);
     64}
     65
     66static unsigned char amiga_frob_control( struct parport *p, unsigned char mask, unsigned char val)
     67{
     68	unsigned char old;
     69
     70	pr_debug("frob_control mask %02x, value %02x\n", mask, val);
     71	old = amiga_read_control(p);
     72	amiga_write_control(p, (old & ~mask) ^ val);
     73	return old;
     74}
     75
     76static unsigned char status_amiga_to_pc(unsigned char status)
     77{
     78	unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR;
     79
     80	if (status & 1) /* Busy */
     81		ret &= ~PARPORT_STATUS_BUSY;
     82	if (status & 2) /* PaperOut */
     83		ret |= PARPORT_STATUS_PAPEROUT;
     84	if (status & 4) /* Selected */
     85		ret |= PARPORT_STATUS_SELECT;
     86	/* the rest is not connected or handled autonomously in hardware */
     87
     88	return ret;
     89}
     90
     91static unsigned char amiga_read_status(struct parport *p)
     92{
     93	unsigned char status;
     94
     95	status = status_amiga_to_pc(ciab.pra & 7);
     96	pr_debug("read_status %02x\n", status);
     97	return status;
     98}
     99
    100static void amiga_enable_irq(struct parport *p)
    101{
    102	enable_irq(IRQ_AMIGA_CIAA_FLG);
    103}
    104
    105static void amiga_disable_irq(struct parport *p)
    106{
    107	disable_irq(IRQ_AMIGA_CIAA_FLG);
    108}
    109
    110static void amiga_data_forward(struct parport *p)
    111{
    112	pr_debug("forward\n");
    113	ciaa.ddrb = 0xff; /* all pins output */
    114	mb();
    115}
    116
    117static void amiga_data_reverse(struct parport *p)
    118{
    119	pr_debug("reverse\n");
    120	ciaa.ddrb = 0; /* all pins input */
    121	mb();
    122}
    123
    124static void amiga_init_state(struct pardevice *dev, struct parport_state *s)
    125{
    126	s->u.amiga.data = 0;
    127	s->u.amiga.datadir = 255;
    128	s->u.amiga.status = 0;
    129	s->u.amiga.statusdir = 0;
    130}
    131
    132static void amiga_save_state(struct parport *p, struct parport_state *s)
    133{
    134	mb();
    135	s->u.amiga.data = ciaa.prb;
    136	s->u.amiga.datadir = ciaa.ddrb;
    137	s->u.amiga.status = ciab.pra & 7;
    138	s->u.amiga.statusdir = ciab.ddra & 7;
    139	mb();
    140}
    141
    142static void amiga_restore_state(struct parport *p, struct parport_state *s)
    143{
    144	mb();
    145	ciaa.prb = s->u.amiga.data;
    146	ciaa.ddrb = s->u.amiga.datadir;
    147	ciab.pra |= (ciab.pra & 0xf8) | s->u.amiga.status;
    148	ciab.ddra |= (ciab.ddra & 0xf8) | s->u.amiga.statusdir;
    149	mb();
    150}
    151
    152static struct parport_operations pp_amiga_ops = {
    153	.write_data	= amiga_write_data,
    154	.read_data	= amiga_read_data,
    155
    156	.write_control	= amiga_write_control,
    157	.read_control	= amiga_read_control,
    158	.frob_control	= amiga_frob_control,
    159
    160	.read_status	= amiga_read_status,
    161
    162	.enable_irq	= amiga_enable_irq,
    163	.disable_irq	= amiga_disable_irq,
    164
    165	.data_forward	= amiga_data_forward,
    166	.data_reverse	= amiga_data_reverse,
    167
    168	.init_state	= amiga_init_state,
    169	.save_state	= amiga_save_state,
    170	.restore_state	= amiga_restore_state,
    171
    172	.epp_write_data	= parport_ieee1284_epp_write_data,
    173	.epp_read_data	= parport_ieee1284_epp_read_data,
    174	.epp_write_addr	= parport_ieee1284_epp_write_addr,
    175	.epp_read_addr	= parport_ieee1284_epp_read_addr,
    176
    177	.ecp_write_data	= parport_ieee1284_ecp_write_data,
    178	.ecp_read_data	= parport_ieee1284_ecp_read_data,
    179	.ecp_write_addr	= parport_ieee1284_ecp_write_addr,
    180
    181	.compat_write_data	= parport_ieee1284_write_compat,
    182	.nibble_read_data	= parport_ieee1284_read_nibble,
    183	.byte_read_data		= parport_ieee1284_read_byte,
    184
    185	.owner		= THIS_MODULE,
    186};
    187
    188/* ----------- Initialisation code --------------------------------- */
    189
    190static int __init amiga_parallel_probe(struct platform_device *pdev)
    191{
    192	struct parport *p;
    193	int err;
    194
    195	ciaa.ddrb = 0xff;
    196	ciab.ddra &= 0xf8;
    197	mb();
    198
    199	p = parport_register_port((unsigned long)&ciaa.prb, IRQ_AMIGA_CIAA_FLG,
    200				   PARPORT_DMA_NONE, &pp_amiga_ops);
    201	if (!p)
    202		return -EBUSY;
    203
    204	err = request_irq(IRQ_AMIGA_CIAA_FLG, parport_irq_handler, 0, p->name,
    205			  p);
    206	if (err)
    207		goto out_irq;
    208
    209	pr_info("%s: Amiga built-in port using irq\n", p->name);
    210	/* XXX: set operating mode */
    211	parport_announce_port(p);
    212
    213	platform_set_drvdata(pdev, p);
    214
    215	return 0;
    216
    217out_irq:
    218	parport_put_port(p);
    219	return err;
    220}
    221
    222static int __exit amiga_parallel_remove(struct platform_device *pdev)
    223{
    224	struct parport *port = platform_get_drvdata(pdev);
    225
    226	parport_remove_port(port);
    227	if (port->irq != PARPORT_IRQ_NONE)
    228		free_irq(IRQ_AMIGA_CIAA_FLG, port);
    229	parport_put_port(port);
    230	return 0;
    231}
    232
    233static struct platform_driver amiga_parallel_driver = {
    234	.remove = __exit_p(amiga_parallel_remove),
    235	.driver   = {
    236		.name	= "amiga-parallel",
    237	},
    238};
    239
    240module_platform_driver_probe(amiga_parallel_driver, amiga_parallel_probe);
    241
    242MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
    243MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port");
    244MODULE_LICENSE("GPL");
    245MODULE_ALIAS("platform:amiga-parallel");