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 34 static struct parport *this_port = NULL; 35 36 static 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 44 static 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 #if 0 51 static unsigned char control_pc_to_amiga(unsigned char control) 52 { 53 unsigned char ret = 0; 54 55 if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */ 56 ; 57 if (control & PARPORT_CONTROL_INIT) /* INITP */ 58 /* reset connected to cpu reset pin */; 59 if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */ 60 /* Not connected */; 61 if (control & PARPORT_CONTROL_STROBE) /* Strobe */ 62 /* Handled only directly by hardware */; 63 return ret; 64 } 65 #endif 66 67 static unsigned char control_amiga_to_pc(unsigned char control) 68 { 69 return PARPORT_CONTROL_SELECT | 70 PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE; 71 /* fake value: interrupt enable, select in, no reset, 72 no autolf, no strobe - seems to be closest the wiring diagram */ 73 } 74 75 static void amiga_write_control(struct parport *p, unsigned char control) 76 { 77 DPRINTK(KERN_DEBUG "write_control %02x\n",control); 78 /* No implementation possible */ 79 } 80 81 static unsigned char amiga_read_control( struct parport *p) 82 { 83 DPRINTK(KERN_DEBUG "read_control \n"); 84 return control_amiga_to_pc(0); 85 } 86 87 static unsigned char amiga_frob_control( struct parport *p, unsigned char mask, unsigned char val) 88 { 89 unsigned char old; 90 91 DPRINTK(KERN_DEBUG "frob_control mask %02x, value %02x\n",mask,val); 92 old = amiga_read_control(p); 93 amiga_write_control(p, (old & ~mask) ^ val); 94 return old; 95 } 96 97 #if 0 /* currently unused */ 98 static unsigned char status_pc_to_amiga(unsigned char status) 99 { 100 unsigned char ret = 1; 101 102 if (status & PARPORT_STATUS_BUSY) /* Busy */ 103 ret &= ~1; 104 if (status & PARPORT_STATUS_ACK) /* Ack */ 105 /* handled in hardware */; 106 if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */ 107 ret |= 2; 108 if (status & PARPORT_STATUS_SELECT) /* select */ 109 ret |= 4; 110 if (status & PARPORT_STATUS_ERROR) /* error */ 111 /* not connected */; 112 return ret; 113 } 114 #endif 115 116 static unsigned char status_amiga_to_pc(unsigned char status) 117 { 118 unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR; 119 120 if (status & 1) /* Busy */ 121 ret &= ~PARPORT_STATUS_BUSY; 122 if (status & 2) /* PaperOut */ 123 ret |= PARPORT_STATUS_PAPEROUT; 124 if (status & 4) /* Selected */ 125 ret |= PARPORT_STATUS_SELECT; 126 /* the rest is not connected or handled autonomously in hardware */ 127 128 return ret; 129 } 130 131 static unsigned char amiga_read_status(struct parport *p) 132 { 133 unsigned char status; 134 135 status = status_amiga_to_pc(ciab.pra & 7); 136 DPRINTK(KERN_DEBUG "read_status %02x\n", status); 137 return status; 138 } 139 140 static void amiga_enable_irq(struct parport *p) 141 { 142 enable_irq(IRQ_AMIGA_CIAA_FLG); 143 } 144 145 static void amiga_disable_irq(struct parport *p) 146 { 147 disable_irq(IRQ_AMIGA_CIAA_FLG); 148 } 149 150 static void amiga_data_forward(struct parport *p) 151 { 152 DPRINTK(KERN_DEBUG "forward\n"); 153 ciaa.ddrb = 0xff; /* all pins output */ 154 mb(); 155 } 156 157 static void amiga_data_reverse(struct parport *p) 158 { 159 DPRINTK(KERN_DEBUG "reverse\n"); 160 ciaa.ddrb = 0; /* all pins input */ 161 mb(); 162 } 163 164 static void amiga_init_state(struct pardevice *dev, struct parport_state *s) 165 { 166 s->u.amiga.data = 0; 167 s->u.amiga.datadir = 255; 168 s->u.amiga.status = 0; 169 s->u.amiga.statusdir = 0; 170 } 171 172 static void amiga_save_state(struct parport *p, struct parport_state *s) 173 { 174 mb(); 175 s->u.amiga.data = ciaa.prb; 176 s->u.amiga.datadir = ciaa.ddrb; 177 s->u.amiga.status = ciab.pra & 7; 178 s->u.amiga.statusdir = ciab.ddra & 7; 179 mb(); 180 } 181 182 static void amiga_restore_state(struct parport *p, struct parport_state *s) 183 { 184 mb(); 185 ciaa.prb = s->u.amiga.data; 186 ciaa.ddrb = s->u.amiga.datadir; 187 ciab.pra |= (ciab.pra & 0xf8) | s->u.amiga.status; 188 ciab.ddra |= (ciab.ddra & 0xf8) | s->u.amiga.statusdir; 189 mb(); 190 } 191 192 static struct parport_operations pp_amiga_ops = { 193 .write_data = amiga_write_data, 194 .read_data = amiga_read_data, 195 196 .write_control = amiga_write_control, 197 .read_control = amiga_read_control, 198 .frob_control = amiga_frob_control, 199 200 .read_status = amiga_read_status, 201 202 .enable_irq = amiga_enable_irq, 203 .disable_irq = amiga_disable_irq, 204 205 .data_forward = amiga_data_forward, 206 .data_reverse = amiga_data_reverse, 207 208 .init_state = amiga_init_state, 209 .save_state = amiga_save_state, 210 .restore_state = amiga_restore_state, 211 212 .epp_write_data = parport_ieee1284_epp_write_data, 213 .epp_read_data = parport_ieee1284_epp_read_data, 214 .epp_write_addr = parport_ieee1284_epp_write_addr, 215 .epp_read_addr = parport_ieee1284_epp_read_addr, 216 217 .ecp_write_data = parport_ieee1284_ecp_write_data, 218 .ecp_read_data = parport_ieee1284_ecp_read_data, 219 .ecp_write_addr = parport_ieee1284_ecp_write_addr, 220 221 .compat_write_data = parport_ieee1284_write_compat, 222 .nibble_read_data = parport_ieee1284_read_nibble, 223 .byte_read_data = parport_ieee1284_read_byte, 224 225 .owner = THIS_MODULE, 226 }; 227 228 /* ----------- Initialisation code --------------------------------- */ 229 230 static int __init parport_amiga_init(void) 231 { 232 struct parport *p; 233 int err; 234 235 if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_PARALLEL)) 236 return -ENODEV; 237 238 err = -EBUSY; 239 if (!request_mem_region(CIAA_PHYSADDR-1+0x100, 0x100, "parallel")) 240 goto out_mem; 241 242 ciaa.ddrb = 0xff; 243 ciab.ddra &= 0xf8; 244 mb(); 245 246 p = parport_register_port((unsigned long)&ciaa.prb, IRQ_AMIGA_CIAA_FLG, 247 PARPORT_DMA_NONE, &pp_amiga_ops); 248 if (!p) 249 goto out_port; 250 251 err = request_irq(IRQ_AMIGA_CIAA_FLG, parport_irq_handler, 0, p->name, p); 252 if (err) 253 goto out_irq; 254 255 this_port = p; 256 printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name); 257 /* XXX: set operating mode */ 258 parport_announce_port(p); 259 260 return 0; 261 262 out_irq: 263 parport_put_port(p); 264 out_port: 265 release_mem_region(CIAA_PHYSADDR-1+0x100, 0x100); 266 out_mem: 267 return err; 268 } 269 270 static void __exit parport_amiga_exit(void) 271 { 272 parport_remove_port(this_port); 273 if (this_port->irq != PARPORT_IRQ_NONE) 274 free_irq(IRQ_AMIGA_CIAA_FLG, this_port); 275 parport_put_port(this_port); 276 release_mem_region(CIAA_PHYSADDR-1+0x100, 0x100); 277 } 278 279 280 MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>"); 281 MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port"); 282 MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port"); 283 MODULE_LICENSE("GPL"); 284 285 module_init(parport_amiga_init) 286 module_exit(parport_amiga_exit) 287