1
/******************************************************
3
* zexy - implementation file
5
* copyleft (c) IOhannes m zm�lnig
7
* 1999:forum::f�r::uml�ute:2004
9
* institute of electronic music and acoustics (iem)
11
******************************************************
13
* license: GNU General Public License v.2
15
******************************************************/
18
(c) 2000:forum::f�r::uml�ute:2005
20
write to the parallel port
21
extended to write to any port (if we do have permissions)
23
2005-09-28: write to devices instead of hardware-addresses
24
http://people.redhat.com/twaugh/parport/html/ppdev.html
25
TODO: don't lock when multiple objects refer to the same device
26
TODO: allow readonly/writeonly access
27
TODO: test for timeouts,...
30
Olaf Matthes: porting to WindozeNT/2000/XP
31
Thomas Musil: adding "control-output" and "input"
43
/* ----------------------- lpt --------------------- */
49
# ifdef HAVE_LINUX_PPDEV_H
51
# include <sys/ioctl.h>
52
# include <linux/ppdev.h>
53
# include <linux/parport.h>
56
# endif /* HAVE_LINUX_PPDEV_H */
60
/* on windoze everything is so complicated... */
61
extern int read_parport(int port);
62
extern void write_parport(int port, int value);
63
extern int open_port(int port);
65
static int ioperm(int port, int a, int b)
67
if(open_port(port) == -1)return(1);
71
static int iopl(int i)
76
static void sys_outb(unsigned char byte, int port)
78
write_parport(port, byte);
80
static int sys_inb(int port)
82
return read_parport(port);
85
/* thankfully there is linux */
88
static void sys_outb(unsigned char byte, int port)
92
static int sys_inb(int port)
96
# endif /* __WIN32__ */
97
#endif /* Z_WANT_LP */
100
static int count_iopl = 0;
101
static t_class *lpt_class;
108
int device; /* file descriptor of device, in case we are using one ...*/
110
int mode; /* MODE_IOPERM, MODE_IOPL */
113
static void lpt_float(t_lpt *x, t_floatarg f)
117
# ifdef HAVE_LINUX_PPDEV_H
119
ioctl (x->device, PPWDATA, &b);
123
sys_outb(b, x->port+0);
125
#endif /* Z_WANT_LPT */
128
static void lpt_control(t_lpt *x, t_floatarg f)
132
# ifdef HAVE_LINUX_PPDEV_H
134
ioctl (x->device, PPWCONTROL, &b);
138
sys_outb(b, x->port+2);
140
#endif /* Z_WANT_LPT */
143
static void lpt_bang(t_lpt *x)
146
# ifdef HAVE_LINUX_PPDEV_H
149
ioctl (x->device, PPRCONTROL, &b);
150
outlet_float(x->x_obj.ob_outlet, (t_float)b);
154
outlet_float(x->x_obj.ob_outlet, (t_float)sys_inb(x->port+1));
156
#endif /* Z_WANT_LPT */
160
static void *lpt_new(t_symbol *s, int argc, t_atom *argv)
162
t_lpt *x = (t_lpt *)pd_new(lpt_class);
163
char*devname=atom_getsymbol(argv)->s_name;
165
error("lpt: the use of 'lp' has been deprecated; use 'lpt' instead");
168
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("control"));
169
outlet_new(&x->x_obj, &s_float);
175
if ((argc==0)||(argv->a_type==A_FLOAT)) {
176
/* FLOAT specifies a parallel port */
177
switch ((int)((argc)?atom_getfloat(argv):0)) {
188
error("lpt : only lpt0, lpt1 and lpt2 are accessible");
193
/* SYMBOL might be a file or a hex port-number;
194
we ignore the file (device) case by now;
195
LATER think about this
198
x->port=strtol(devname, 0, 16);
200
#ifdef HAVE_LINUX_PPDEV_H
201
x->device = open(devname, O_RDWR);
203
error("lpt: bad device %s", devname);
206
if (ioctl (x->device, PPCLAIM)) {
212
#endif /* HAVE_LINUX_PPDEV_H */
216
if ((x->device<0) && (!x->port || x->port>65535)){
217
post("lpt : bad port %x", x->port);
222
/* this is ugly: when using a named device,
223
* we are currently assuming that we have read/write-access
224
* of course, this is not necessary true
226
/* furthermore, we might also use the object
227
* withOUT write permissions
228
* (just reading the parport)
230
if (x->port && x->port < 0x400){
231
if (ioperm(x->port, 8, 1)) {
233
} else x->mode = MODE_IOPERM;
235
if(x->mode==MODE_NONE){
238
} else x->mode=MODE_IOPL;
242
if(x->mode==MODE_NONE){
243
error("lpt : couldn't get write permissions");
249
post("lpt: connected to device %s", devname);
251
post("lpt: connected to port %x in mode '%s'", x->port, (x->mode==MODE_IOPL)?"iopl":"ioperm");
252
if (x->mode==MODE_IOPL)post("lpt-warning: this might seriously damage your pc...");
254
error("zexy has been compiled without [lpt]!");
256
#endif /* Z_WANT_LPT */
263
static void lpt_free(t_lpt *x)
266
# ifdef HAVE_LINUX_PPDEV_H
268
ioctl (x->device, PPRELEASE);
274
if (x->mode==MODE_IOPERM && ioperm(x->port, 8, 0)) error("lpt: couldn't clean up device");
275
else if (x->mode==MODE_IOPL && (!--count_iopl) && iopl(0))
276
error("lpt: couldn't clean up device");
278
#endif /* Z_WANT_LPT */
282
static void lpt_helper(t_lpt *x)
285
post("\n%c lpt :: direct access to the parallel port", HEARTSYMBOL);
286
post("<byte>\t: write byte to the parallel-port");
287
post("\ncreation:\t\"lpt [<port>]\": connect to parallel port <port> (0..2)");
288
post("\t\t\"lpt <portaddr>\": connect to port @ <portaddr> (hex)");
293
lpt_class = class_new(gensym("lpt"),
294
(t_newmethod)lpt_new, (t_method)lpt_free,
295
sizeof(t_lpt), 0, A_GIMME, 0);
296
class_addcreator((t_newmethod)lpt_new, gensym("lp"), A_GIMME, 0);
298
class_addfloat(lpt_class, (t_method)lpt_float);
299
class_addmethod(lpt_class, (t_method)lpt_control, gensym("control"), A_FLOAT, 0);
300
class_addbang(lpt_class, (t_method)lpt_bang);
302
class_addmethod(lpt_class, (t_method)lpt_helper, gensym("help"), 0);
303
zexy_register("lpt");