1 /* Low-level parallel port routines for the Atari builtin port
2  *
3  * Author: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
4  *
5  * Based on parport_amiga.c.
6  *
7  * The built-in Atari parallel port provides one port at a fixed address
8  * with 8 output data lines (D0 - D7), 1 output control line (STROBE)
9  * and 1 input status line (BUSY) able to cause an interrupt.
10  */
11 
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/parport.h>
15 #include <asm/setup.h>
16 #include <asm/atarihw.h>
17 #include <asm/irq.h>
18 #include <asm/atariints.h>
19 
20 static struct parport *this_port = NULL;
21 
22 static unsigned char
parport_atari_read_data(struct parport * p)23 parport_atari_read_data(struct parport *p)
24 {
25 	unsigned long flags;
26 	unsigned char data;
27 
28 	save_flags(flags);
29 	cli();
30 	sound_ym.rd_data_reg_sel = 15;
31 	data = sound_ym.rd_data_reg_sel;
32 	restore_flags(flags);
33 	return data;
34 }
35 
36 static void
parport_atari_write_data(struct parport * p,unsigned char data)37 parport_atari_write_data(struct parport *p, unsigned char data)
38 {
39 	unsigned long flags;
40 
41 	save_flags(flags);
42 	cli();
43 	sound_ym.rd_data_reg_sel = 15;
44 	sound_ym.wd_data = data;
45 	restore_flags(flags);
46 }
47 
48 static unsigned char
parport_atari_read_control(struct parport * p)49 parport_atari_read_control(struct parport *p)
50 {
51 	unsigned long flags;
52 	unsigned char control = 0;
53 
54 	save_flags(flags);
55 	cli();
56 	sound_ym.rd_data_reg_sel = 14;
57 	if (!(sound_ym.rd_data_reg_sel & (1 << 5)))
58 		control = PARPORT_CONTROL_STROBE;
59 	restore_flags(flags);
60 	return control;
61 }
62 
63 static void
parport_atari_write_control(struct parport * p,unsigned char control)64 parport_atari_write_control(struct parport *p, unsigned char control)
65 {
66 	unsigned long flags;
67 
68 	save_flags(flags);
69 	cli();
70 	sound_ym.rd_data_reg_sel = 14;
71 	if (control & PARPORT_CONTROL_STROBE)
72 		sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5);
73 	else
74 		sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
75 	restore_flags(flags);
76 }
77 
78 static unsigned char
parport_atari_frob_control(struct parport * p,unsigned char mask,unsigned char val)79 parport_atari_frob_control(struct parport *p, unsigned char mask,
80 			   unsigned char val)
81 {
82 	unsigned char old = parport_atari_read_control(p);
83 	parport_atari_write_control(p, (old & ~mask) ^ val);
84 	return old;
85 }
86 
87 static unsigned char
parport_atari_read_status(struct parport * p)88 parport_atari_read_status(struct parport *p)
89 {
90 	return ((mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) |
91 		PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR);
92 }
93 
94 static void
parport_atari_init_state(struct pardevice * d,struct parport_state * s)95 parport_atari_init_state(struct pardevice *d, struct parport_state *s)
96 {
97 }
98 
99 static void
parport_atari_save_state(struct parport * p,struct parport_state * s)100 parport_atari_save_state(struct parport *p, struct parport_state *s)
101 {
102 }
103 
104 static void
parport_atari_restore_state(struct parport * p,struct parport_state * s)105 parport_atari_restore_state(struct parport *p, struct parport_state *s)
106 {
107 }
108 
109 static void
parport_atari_interrupt(int irq,void * dev_id,struct pt_regs * regs)110 parport_atari_interrupt(int irq, void *dev_id, struct pt_regs *regs)
111 {
112 	parport_generic_irq(irq, (struct parport *) dev_id, regs);
113 }
114 
115 static void
parport_atari_enable_irq(struct parport * p)116 parport_atari_enable_irq(struct parport *p)
117 {
118 	enable_irq(IRQ_MFP_BUSY);
119 }
120 
121 static void
parport_atari_disable_irq(struct parport * p)122 parport_atari_disable_irq(struct parport *p)
123 {
124 	disable_irq(IRQ_MFP_BUSY);
125 }
126 
127 static void
parport_atari_data_forward(struct parport * p)128 parport_atari_data_forward(struct parport *p)
129 {
130 	unsigned long flags;
131 
132 	save_flags(flags);
133 	cli();
134 	/* Soundchip port B as output. */
135 	sound_ym.rd_data_reg_sel = 7;
136 	sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x40;
137 	restore_flags(flags);
138 }
139 
140 static void
parport_atari_data_reverse(struct parport * p)141 parport_atari_data_reverse(struct parport *p)
142 {
143 #if 0 /* too dangerous, can kill sound chip */
144 	unsigned long flags;
145 
146 	save_flags(flags);
147 	cli();
148 	/* Soundchip port B as input. */
149 	sound_ym.rd_data_reg_sel = 7;
150 	sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~0x40;
151 	restore_flags(flags);
152 #endif
153 }
154 
155 static void
parport_atari_inc_use_count(void)156 parport_atari_inc_use_count(void)
157 {
158 	MOD_INC_USE_COUNT;
159 }
160 
161 static void
parport_atari_dec_use_count(void)162 parport_atari_dec_use_count(void)
163 {
164 	MOD_DEC_USE_COUNT;
165 }
166 
167 static struct parport_operations parport_atari_ops = {
168 	parport_atari_write_data,
169 	parport_atari_read_data,
170 
171 	parport_atari_write_control,
172 	parport_atari_read_control,
173 	parport_atari_frob_control,
174 
175 	parport_atari_read_status,
176 
177 	parport_atari_enable_irq,
178 	parport_atari_disable_irq,
179 
180 	parport_atari_data_forward,
181 	parport_atari_data_reverse,
182 
183 	parport_atari_init_state,
184 	parport_atari_save_state,
185 	parport_atari_restore_state,
186 
187 	parport_atari_inc_use_count,
188 	parport_atari_dec_use_count,
189 
190 	parport_ieee1284_epp_write_data,
191 	parport_ieee1284_epp_read_data,
192 	parport_ieee1284_epp_write_addr,
193 	parport_ieee1284_epp_read_addr,
194 
195 	parport_ieee1284_ecp_write_data,
196 	parport_ieee1284_ecp_read_data,
197 	parport_ieee1284_ecp_write_addr,
198 
199 	parport_ieee1284_write_compat,
200 	parport_ieee1284_read_nibble,
201 	parport_ieee1284_read_byte,
202 };
203 
204 
205 int __init
parport_atari_init(void)206 parport_atari_init(void)
207 {
208 	struct parport *p;
209 	unsigned long flags;
210 
211 	if (MACH_IS_ATARI) {
212 		save_flags(flags);
213 		cli();
214 		/* Soundchip port A/B as output. */
215 		sound_ym.rd_data_reg_sel = 7;
216 		sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0;
217 		/* STROBE high. */
218 		sound_ym.rd_data_reg_sel = 14;
219 		sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
220 		restore_flags(flags);
221 		/* MFP port I0 as input. */
222 		mfp.data_dir &= ~1;
223 		/* MFP port I0 interrupt on high->low edge. */
224 		mfp.active_edge &= ~1;
225 		p = parport_register_port((unsigned long)&sound_ym.wd_data,
226 					  IRQ_MFP_BUSY, PARPORT_DMA_NONE,
227 					  &parport_atari_ops);
228 		if (!p)
229 			return 0;
230 		if (request_irq(IRQ_MFP_BUSY, parport_atari_interrupt,
231 				IRQ_TYPE_SLOW, p->name, p)) {
232 			parport_unregister_port (p);
233 			return 0;
234 		}
235 
236 		this_port = p;
237 		printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name);
238 		parport_proc_register(p);
239 
240 		parport_announce_port (p);
241 
242 		return 1;
243 	}
244 	return 0;
245 }
246 
247 #ifdef MODULE
248 
249 MODULE_AUTHOR("Andreas Schwab");
250 MODULE_DESCRIPTION("Parport Driver for Atari builtin Port");
251 MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port");
252 MODULE_LICENSE("GPL");
253 
254 int
init_module(void)255 init_module(void)
256 {
257 	return parport_atari_init() ? 0 : -ENODEV;
258 }
259 
260 void
cleanup_module(void)261 cleanup_module(void)
262 {
263 	if (this_port->irq != PARPORT_IRQ_NONE)
264 		free_irq(IRQ_MFP_BUSY, this_port);
265 	parport_proc_unregister(this_port);
266 	parport_unregister_port(this_port);
267 }
268 #endif
269