[PARPORT] Re: L68K: Amiga-Parport-driver


Jerome Thoen (thoen@mail.dotcom.fr)
Sat, 29 Aug 1998 01:18:42 +0200


Hi,

Last year I tried to do a parport driver for Amiga builtin parallel port.
Do to lack of time I didn't finish it and forgot it... I see that someone
is trying to do such a driver, so this is my work, perhaps it will help you
and save you some time.

parport_amiga.c
---------------
/* Low-level parallel-port routines for Amiga hardware.
 *
 * Author: Jerome Thoen <jthoen@hol.fr>
 *
 * based on work by Phil Blundell <Philip.Blundell@pobox.com>
 *
 * Amiga hardware provides one parallel port at a fixed address.
 * There are 8 bi-directional data lines (D0-D7), 3 bi-directional status
lines
 * (BUSY, POUT, SEL), 1 output control line (/STROBE), and 1 input control
line
 * (/ACK).
 * Due to lack of control lines, Amiga and PC-style parallel ports are not
 * fully compatible. Thus only SPP mode is supported with the status lines
 * listed above.
 */

#include <linux/stddef.h>
#include <linux/tasks.h>

#include <asm/ptrace.h>
#include <asm/io.h>

#include <linux/module.h>
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/malloc.h>

#include <linux/parport.h>

#include <asm/setup.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>

/* We need a copy of the data port to be compatible with SPP : we must read
   the value on the port, not the value currently on data lines */
static unsigned int data_copy;

static void parport_amiga_null_intr_func(int irq, void *dev_id, struct
pt_regs *regs)
{
        /* Null function - does nothing */
}

void parport_amiga_write_data(struct parport *p, unsigned int d)
{
        /* /STROBE is triggered by hardware as soon as a byte is written on the
           port. /STROBE is high by default.
           
           That's why we don't need to trigger /STROBE line by software
           when writing to the port (we can't anyway)

           This feature cannot be disabled */
        ciaa.prb = data_copy = d;
}

unsigned int parport_amiga_read_data(struct parport *p)
{
        return data_copy;
}

void parport_amiga_write_control(struct parport *p, unsigned int d)
{
        /* nothing to do */
}

unsigned int parport_amiga_read_control(struct parport *p)
{
        return 0; /* nothing to do */
}

unsigned int parport_amiga_frob_control(struct parport *p, unsigned int
mask, unsigned int val)
{
        return 0; /* nothing to do */
}

void parport_amiga_write_status(struct parport *p, unsigned int d)
{
        /* converts status bits from PC-style to Amiga */
        ciab.pra = ((d & PARPORT_STATUS_BUSY)? 0 : 1) | \
          ((d & PARPORT_STATUS_PAPEROUT)? 2 : 0) | \
          ((d & PARPORT_STATUS_SELECT)? 4 : 0);
}

unsigned int parport_amiga_read_status(struct parport *p)
{
        /* converts status bits from Amiga to PC-style */
        return (unsigned int)(((ciab.pra & 1)? 0 : PARPORT_STATUS_BUSY) | \
                              ((ciab.pra & 2)? PARPORT_STATUS_PAPEROUT : 0) | \
                              ((ciab.pra & 4)? PARPORT_STATUS_SELECT : 0) | \
                              PARPORT_STATUS_ERROR);
}

void parport_amiga_disable_irq(struct parport *p)
{
        cia_able_irq(&ciaa_base, CIA_ICR_FLG);
}

void parport_amiga_enable_irq(struct parport *p)
{
        /* IRQ is generated whenever /ACK line goes active (level low). */
        cia_set_irq(&ciaa_base, CIA_ICR_FLG);
        cia_able_irq(&ciaa_base, CIA_ICR_FLG | CIA_ICR_SETCLR);
}

void parport_amiga_release_resources(struct parport *p)
{
        if (p->irq != PARPORT_IRQ_NONE)
                free_irq(p->irq, NULL);
        release_region(p->base, p->size);
}

int parport_amiga_claim_resources(struct parport *p)
{
        /* FIXME check that resources are free */
        if (p->irq != PARPORT_IRQ_NONE)
                request_irq(p->irq, parport_amiga_null_intr_func, 0, p->name, NULL);
        request_region(p->base, p->size, p->name);
        return 0;
}

void parport_amiga_inc_use_count(void)
{
#ifdef MODULE
        MOD_INC_USE_COUNT;
#endif
}

void parport_amiga_dec_use_count(void)
{
#ifdef MODULE
        MOD_DEC_USE_COUNT;
#endif
}

struct parport_operations parport_amiga_ops =
{
        parport_amiga_write_data,
        parport_amiga_read_data,

        parport_amiga_write_control,
        parport_amiga_read_control,
        parport_amiga_frob_control,

        NULL, /* write_econtrol */
        NULL, /* read_econtrol */
        NULL, /* frob_econtrol */

        parport_amiga_write_status,
        parport_amiga_read_status,

        NULL, /* write_fifo */
        NULL, /* read_fifo */
        
        NULL, /* change_mode */
        
        parport_amiga_release_resources,
        parport_amiga_claim_resources,
        
        NULL, /* epp_write_block */
        NULL, /* epp_read_block */

        NULL, /* ecp_write_block */
        NULL, /* ecp_read_block */
        
        NULL, /* save_state */
        NULL, /* restore_state */

        parport_amiga_enable_irq,
        parport_amiga_disable_irq,
        NULL, /* examine_irq */

        parport_amiga_inc_use_count,
        parport_amiga_dec_use_count
};

/* --- Initialisation code -------------------------------- */

int parport_amiga_init(void)
{
        struct parport *p;

        if (!(MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)))
                return 0;

        if (check_region(&ciaa.prb, 1))
                return 0;
        
               if (!(p = parport_register_port(&ciaa.prb, IRQ_AMIGA_CIAA_FLG,
                                        PARPORT_DMA_NONE, &parport_amiga_ops)))
                return 0;

        p->modes = PARPORT_MODE_PCSPP;
        p->size = 1;

        printk(KERN_INFO "%s: Amiga builtin parallel port at 0x%lx, using irq
%d\n",
               p->name,
               p->base,
               p->irq);
        parport_proc_register(p);
        p->flags |= PARPORT_FLAG_COMA;

        /* Initialize port, setting directions */

        ciaa.ddrb = 0xff;
        ciab.ddra &= ~0x03;
        parport_amiga_write_data(p, 0);

        if (parport_probe_hook)
                (*parport_probe_hook)(p);

        return 1;
}

#ifdef MODULE
int init_module(void)
{
        return (parport_amiga_init()?0:1);
}

void cleanup_module(void)
{
        struct parport *p = parport_enumerate(), *tmp;
        while (p) {
                tmp = p->next;
                if (p->modes & PARPORT_MODE_PCSPP) {
                        if (!(p->flags & PARPORT_FLAG_COMA))
                                parport_quiesce(p);
                        parport_proc_unregister(p);
                        parport_unregister_port(p);
                }
                p = tmp;
        }
}
#endif

-- To unsubscribe, send mail to: linux-parport-request@torque.net --
-- with the single word "unsubscribe" in the body of the message. --



This archive was generated by hypermail 2.0b3 on Wed 30 Dec 1998 - 10:18:09 EST