linux/drivers/parport/parport_atari.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Low-level parallel port routines for the Atari builtin port
   3 *
   4 * Author: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
   5 *
   6 * Based on parport_amiga.c.
   7 *
   8 * The built-in Atari parallel port provides one port at a fixed address
   9 * with 8 output data lines (D0 - D7), 1 output control line (STROBE)
  10 * and 1 input status line (BUSY) able to cause an interrupt.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/init.h>
  15#include <linux/parport.h>
  16#include <linux/interrupt.h>
  17#include <asm/setup.h>
  18#include <asm/atarihw.h>
  19#include <asm/irq.h>
  20#include <asm/atariints.h>
  21
  22static struct parport *this_port;
  23
  24static unsigned char
  25parport_atari_read_data(struct parport *p)
  26{
  27        unsigned long flags;
  28        unsigned char data;
  29
  30        local_irq_save(flags);
  31        sound_ym.rd_data_reg_sel = 15;
  32        data = sound_ym.rd_data_reg_sel;
  33        local_irq_restore(flags);
  34        return data;
  35}
  36
  37static void
  38parport_atari_write_data(struct parport *p, unsigned char data)
  39{
  40        unsigned long flags;
  41
  42        local_irq_save(flags);
  43        sound_ym.rd_data_reg_sel = 15;
  44        sound_ym.wd_data = data;
  45        local_irq_restore(flags);
  46}
  47
  48static unsigned char
  49parport_atari_read_control(struct parport *p)
  50{
  51        unsigned long flags;
  52        unsigned char control = 0;
  53
  54        local_irq_save(flags);
  55        sound_ym.rd_data_reg_sel = 14;
  56        if (!(sound_ym.rd_data_reg_sel & (1 << 5)))
  57                control = PARPORT_CONTROL_STROBE;
  58        local_irq_restore(flags);
  59        return control;
  60}
  61
  62static void
  63parport_atari_write_control(struct parport *p, unsigned char control)
  64{
  65        unsigned long flags;
  66
  67        local_irq_save(flags);
  68        sound_ym.rd_data_reg_sel = 14;
  69        if (control & PARPORT_CONTROL_STROBE)
  70                sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5);
  71        else
  72                sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
  73        local_irq_restore(flags);
  74}
  75
  76static unsigned char
  77parport_atari_frob_control(struct parport *p, unsigned char mask,
  78                           unsigned char val)
  79{
  80        unsigned char old = parport_atari_read_control(p);
  81        parport_atari_write_control(p, (old & ~mask) ^ val);
  82        return old;
  83}
  84
  85static unsigned char
  86parport_atari_read_status(struct parport *p)
  87{
  88        return ((st_mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) |
  89                PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR);
  90}
  91
  92static void
  93parport_atari_init_state(struct pardevice *d, struct parport_state *s)
  94{
  95}
  96
  97static void
  98parport_atari_save_state(struct parport *p, struct parport_state *s)
  99{
 100}
 101
 102static void
 103parport_atari_restore_state(struct parport *p, struct parport_state *s)
 104{
 105}
 106
 107static void
 108parport_atari_enable_irq(struct parport *p)
 109{
 110        enable_irq(IRQ_MFP_BUSY);
 111}
 112
 113static void
 114parport_atari_disable_irq(struct parport *p)
 115{
 116        disable_irq(IRQ_MFP_BUSY);
 117}
 118
 119static void
 120parport_atari_data_forward(struct parport *p)
 121{
 122        unsigned long flags;
 123
 124        local_irq_save(flags);
 125        /* Soundchip port B as output. */
 126        sound_ym.rd_data_reg_sel = 7;
 127        sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x40;
 128        local_irq_restore(flags);
 129}
 130
 131static void
 132parport_atari_data_reverse(struct parport *p)
 133{
 134}
 135
 136static struct parport_operations parport_atari_ops = {
 137        .write_data     = parport_atari_write_data,
 138        .read_data      = parport_atari_read_data,
 139
 140        .write_control  = parport_atari_write_control,
 141        .read_control   = parport_atari_read_control,
 142        .frob_control   = parport_atari_frob_control,
 143
 144        .read_status    = parport_atari_read_status,
 145
 146        .enable_irq     = parport_atari_enable_irq,
 147        .disable_irq    = parport_atari_disable_irq,
 148
 149        .data_forward   = parport_atari_data_forward,
 150        .data_reverse   = parport_atari_data_reverse,
 151
 152        .init_state     = parport_atari_init_state,
 153        .save_state     = parport_atari_save_state,
 154        .restore_state  = parport_atari_restore_state,
 155
 156        .epp_write_data = parport_ieee1284_epp_write_data,
 157        .epp_read_data  = parport_ieee1284_epp_read_data,
 158        .epp_write_addr = parport_ieee1284_epp_write_addr,
 159        .epp_read_addr  = parport_ieee1284_epp_read_addr,
 160
 161        .ecp_write_data = parport_ieee1284_ecp_write_data,
 162        .ecp_read_data  = parport_ieee1284_ecp_read_data,
 163        .ecp_write_addr = parport_ieee1284_ecp_write_addr,
 164
 165        .compat_write_data      = parport_ieee1284_write_compat,
 166        .nibble_read_data       = parport_ieee1284_read_nibble,
 167        .byte_read_data         = parport_ieee1284_read_byte,
 168
 169        .owner          = THIS_MODULE,
 170};
 171
 172
 173static int __init parport_atari_init(void)
 174{
 175        struct parport *p;
 176        unsigned long flags;
 177
 178        if (MACH_IS_ATARI) {
 179                local_irq_save(flags);
 180                /* Soundchip port A/B as output. */
 181                sound_ym.rd_data_reg_sel = 7;
 182                sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0;
 183                /* STROBE high. */
 184                sound_ym.rd_data_reg_sel = 14;
 185                sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
 186                local_irq_restore(flags);
 187                /* MFP port I0 as input. */
 188                st_mfp.data_dir &= ~1;
 189                /* MFP port I0 interrupt on high->low edge. */
 190                st_mfp.active_edge &= ~1;
 191                p = parport_register_port((unsigned long)&sound_ym.wd_data,
 192                                          IRQ_MFP_BUSY, PARPORT_DMA_NONE,
 193                                          &parport_atari_ops);
 194                if (!p)
 195                        return -ENODEV;
 196                if (request_irq(IRQ_MFP_BUSY, parport_irq_handler, 0, p->name,
 197                                p)) {
 198                        parport_put_port (p);
 199                        return -ENODEV;
 200                }
 201
 202                this_port = p;
 203                pr_info("%s: Atari built-in port using irq\n", p->name);
 204                parport_announce_port (p);
 205
 206                return 0;
 207        }
 208        return -ENODEV;
 209}
 210
 211static void __exit parport_atari_exit(void)
 212{
 213        parport_remove_port(this_port);
 214        if (this_port->irq != PARPORT_IRQ_NONE)
 215                free_irq(IRQ_MFP_BUSY, this_port);
 216        parport_put_port(this_port);
 217}
 218
 219MODULE_AUTHOR("Andreas Schwab");
 220MODULE_DESCRIPTION("Parport Driver for Atari builtin Port");
 221MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port");
 222MODULE_LICENSE("GPL");
 223
 224module_init(parport_atari_init)
 225module_exit(parport_atari_exit)
 226