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