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