Programação de Sistemas
Controlador de impressora
por interface paralela
Programação de Sistemas
Centronics : 1/33
Introdução (1)
• A interface paralela IEEE1284, ou Centronics, permite
dois equipamentos trocar informação de 8 bits em
simultâneo.
– Usa ficha DB25
– Velocidades de transferência até 150Kbps, com cabo até 10m.
– Pinos distribuídos por:
•
•
•
•
8 bidireccionais para porto OUTPUT (RW)
5 para porto STATUS(R)
4 para porto CONTROL(RW)
8 ligados ao GND
Programação de Sistemas
Centronics : 2/33
Introdução (2)
• Os 3 portos ocupam os seguintes endereços
– Endereço BASE: Output
– Endereço BASE+1: Status
– Endereço BASE+2: Control
• IEEE1284 especifica 4 modos de operação
– Compatível: modo básico, assíncrono.
– Nibble: do periférico para anfitrião (“host”) em mensagens de 4
bits e a metade da velocidade.
– Byte: do periférico para anfitrião em mensagens de 8 bits.
(combinado com modo compatível faz o porto ser designado por
Bidireccional)
– EPP, ECP: conexão half-duplex.
Programação de Sistemas
Centronics : 3/33
Introdução (3)
Ligado ao IRQ7
Status register
Bit
Pino
Sinal
Significado
3
15
Error/
Perifério em erro
4
13
Select
Perifério seleccionado
5
12
PaperOut
Sem papel
6
10
Ack/
Aceitou dados (mantém LOW durante ~ 5µs)
7
11
Busy
Perifério ocupado
Control register
Bit
Pino
Sinal
0
1
Strobe/
Dados disponíveis (manter LOW durante min 5µs)
1
14
AutoLineFeed/
Ordem para executar automaticamente salto de linha
2
16
Initialize/
Ordem para inicializar (manter LOW durante min 5µs)
3
17
SelectPrinter/
Seleccionar o periférico
Programação de Sistemas
Significado
Centronics : 4/33
Introdução (4)
• O controlador vai interagir com impressora em modo
E/S programada (“pooling”).
• Diagrama temporal de envio de um Byte para o
periférico.
Programação de Sistemas
Centronics : 5/33
Introdução (5)
• Uso do porto paralelo para controlar um step
motor
Programação de Sistemas
Centronics : 6/33
Impressora (1)
• Pretende-se implementar um controlador
para uma impressora HP LaserJet 6.
• Impressora de baixo custo, 600 dpi,
velocidade 4 páginas/min, alimentador
pouco fiável, com interface paralela.
• Aceita apenas a descrição de páginas em
PCL-Printer Command Language.
• Entradas a implementar: open,
release e write.
Programação de Sistemas
Centronics : 7/33
Impressora (2)
• Comandos da impressora expressos na linguagem PJLPrinter Job Language da HP.
• Uma tarefa de impressão segue a seguinte estrutura
<ESC>%-12345X
Comandos controlo da tarefa
<ESC>E
Página 1
…
Página n
<ESC>E
<ESC>%-12345X
Programação de Sistemas
Centronics : 8/33
Impressora (3)
• Consultar manual PCL em
http://h20000.www2.hp.com/bc//docs/support/SupportManual/bpl13210/bpl13210.pdf
• A linguagem de descrição das páginas PCL-Printer
Command Language, da HP, é implementada por todos os
fabricantes de impressoras.
• Outra linguagem de descrição de páginas, bastante
divulgada, é o POSTSCRIPT.
• <ESC>%-12345X é designado por UEL-Universal Exit
Language, delimitando todas as tarefas
Programação de Sistemas
Centronics : 9/33
Impressora (4)
• Os comandos PCL possuem o formato
<ESC>CparameterizadoCgrupo#Cterminação
Opcionalmente mais dois campos,
Cparâmetro#
quantidade
• O sistema de coordenadas é
definido pela figura
• O texto é impresso apenas
dentro das margens (tudo o
que saia é eliminado)
Programação de Sistemas
Margens
X
(0,0)
Y
Centronics : 10/33
Impressora (5)
•
Comandos PCL de controlo de página: exemplos
### tamanho página (para A4, #=26)
### fonte papel (para manual, #=2)
### orientação papel (para vertical, #=0)
<ESC>&l#A
<ESC>&l#H
<ESC>&l#O
•
Fontes determinadas por parâmetros na seguinte ordem:
1.
2.
3.
4.
5.
6.
7.
Conjunto de símbolos (PC-8,…)
Espaçamento ocupado por cada caractere (igual ou distinto)
Pitch (número de caracteres impressos numa polegada horizontal)
Altura (diferença em pontos=1/72 polegadas)
Estilo (postura-ex:itálico, largura e estrutura-ex:sombreado)
Espessura (“stroke weight”)
Tipo de letra (Courier,CG Times,…)
Programação de Sistemas
Hp
Centronics : 11/33
Impressora (6)
<ESC>(0U<ESC>(s1p14v0s3b4101T
ASCII
CG Times
altura
espaçamento proporcional
• Comandos PCL de posicionamento
<ESC>*p#x#Y
### posiciona cursor na linha, coluna
• Terminação de linha
<ESC>&k#G
Programação de Sistemas
### para #=2, LF substituído por CR+LF
Centronics : 12/33
Interface
• Funções a implementar:
int init_module(void)
void cleanup_module(void)
int parport_open(struct inode *inode,
struct file *filp)
int parport_close(struct inode *inode,
struct file *filp)
ssize_t parport_write(struct file *filp,
char *buf, size_t count, loff_t *f_pos)
Inicialização módulo
Finalização módulo
Abertura ficheiro
Fecho ficheiro
Escrita Bytes
• Inicialização da impressora e comandos PCL de
configuração inseridos na função de abertura do ficheiro.
• Exemplifica-se o controlador de impressora em 2 modos:
– E/S programada
– Interrupções
Programação de Sistemas
Centronics : 13/33
Interface modo E/S programada (1)
#include
#include
#include
#include
#include
#include
#include
<linux/module.h>
<linux/kernel.h>
<linux/fs.h>
<linux/ioport.h>
<linux/errno.h>
<asm/io.h>
<asm/delay.h>
/* struct file_operations,register_chrdev */
/* request_region */
/* error codes */
/* inb,outb */
/* udelay */
#define BASE 0x378
#define NPORTS 8
#define MDN 240
MODULE_LICENSE("GPL");
int parport_open(struct inode *, struct file *);
int parport_release(struct inode *, struct file *);
ssize_t parport_write(struct file *, char *, size_t, loff_t *);
Programação de Sistemas
Centronics : 14/33
Interface modo E/S programada (2)
struct file_operations parport_ops={
.owner
= THIS_MODULE,
.write
= parport_write,
.open
= parport_open,
.release = parport_release
};
#define
#define
#define
#define
PARPORT_CONTROL_STROBE
PARPORT_CONTROL_AUTOFD
PARPORT_CONTROL_INIT
PARPORT_CONTROL_SELECT
0x1
0x2
0x4
0x8
#define
#define
#define
#define
#define
PARPORT_STATUS_ERROR
PARPORT_STATUS_SELECT
PARPORT_STATUS_PAPEROUT
PARPORT_STATUS_ACK
PARPORT_STATUS_BUSY
0x8
0x10
0x20
0x40
0x80
Programação de Sistemas
Centronics : 15/33
Interface modo E/S programada (3)
char uel[9] = {'\x1b','%','-','1','2','3','4','5','X'};
char printerReset[2] = {'\x1b','E'};
/* mantem-se a calha de alimentacao */
char paperSource[5] = {'\x1b','&','l','0','H'};
/* tamanho papel, A4=26 */
char paperSize[6] = {'\x1b','&','l','2','6','A'};
/* margem de topo 12 linhas */
char printerTop[6] = {'\x1b','&','l','1','2','E'};
/* terminacao linha 2-CR=CR, LF=CR+LF, FF=FF */
char lineTermination[5] = {'\x1b','&','k','2','G'};
/* selecciona simbolos de conjunto PC-8, espaçamento proporcional, altura 14 pt,
estilo direito, espessura negrito, fonte Times */
char fontSet[22] =
{'\x1b','(','1','0','U','\x1b','(','s','1','p','1','4','v','0',
's','3','b','4','1','0','1','T'};
char dev_name[] = "Polling parport";
Programação de Sistemas
Centronics : 16/33
Interface modo E/S programada (4)
int init_module(void) {
int result = register_chrdev(MDN,dev_name,&parport_ops);
if (result<0) {
printk(KERN_WARNING "can't get major %d\n",MDN);
return result; }
printk(KERN_INFO "Parport_ops installed!\n");
return 0; }
void cleanup_module(void) {
unregister_chrdev(MDN,dev_name);
printk(KERN_INFO "Parport_ops removed!\n"); }
int parport_release(struct inode *inode, struct file *filp){
/* close device */
return 0; }
Programação de Sistemas
Centronics : 17/33
Interface modo E/S programada (5)
int parport_open(struct inode *inode, struct file *filp) {
/* open device */
outb(~(PARPORT_CONTROL_INIT | PARPORT_CONTROL_SELECT |
PARPORT_CONTROL_AUTOFD), BASE+2);
udelay(5);
outb(0xff,BASE+2);
/* PCL commands */
parport_write( NULL,&printerReset[0],2,NULL );
parport_write( NULL,&paperSource[0],5,NULL );
parport_write( NULL,&paperSize[0],6,NULL );
parport_write( NULL,&printerTop[0],6,NULL );
parport_write( NULL,&lineTermination[0],5,NULL) ;
parport_write( NULL,&fontSet[0],22,NULL );
return 0;
/* success */
}
Programação de Sistemas
Centronics : 18/33
Interface modo E/S programada (6)
ssize_t parport_write(struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
/* Writes buf to the Data port */
char *plocal=buf;
ssize_t wrote=0;
unsigned char status, data;
while(wrote<count) {
for (;;) {
/* NOTA: espera activa que a impressora esteja disponível */
status = inb(BASE+1);
status = status & (PARPORT_STATUS_BUSY | PARPORT_STATUS_ERROR);
if ( status == PARPORT_STATUS_ERROR ) break;
udelay(50); }
/* Set the data lines */
data = *plocal++; outb(data,BASE);
udelay(1);
/* Delay for a bit */
/* Pulse strobe */
outb(PARPORT_CONTROL_AUTOFD |
PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT, BASE+2);
udelay(5);
/* End the pulse */
outb(PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE |
PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT, BASE+2);
wrote++; }
return wrote; }
Programação de Sistemas
Centronics : 19/33
Interface modo interrupção (1)
#include
#include
#include
#include
#include
#include
#include
#include
<linux/module.h>
<linux/kernel.h>
<linux/fs.h>
<asm/io.h>
<asm/delay.h>
<linux/sched.h>
<linux/interrupt.h>
<asm/semaphore.h>
/*
/*
/*
/*
struct file_operations,register_chrdev */
inb,outb */
udelay */
request_irq */
#define BASE 0x378
#define IRQ 7
/* NOTA: novo! */
#define MDN 240
MODULE_LICENSE("GPL");
int parport_open(struct inode *, struct file *);
int parport_release(struct inode *, struct file *);
ssize_t parport_write(struct file *filp, const char *buf, size_t count,
loff_t *f_pos);
Programação de Sistemas
Centronics : 20/33
Interface modo interrupção (2)
struct file_operations parport_ops={
.owner = THIS_MODULE,
.write = parport_write,
.open = parport_open,
.release = parport_release
};
#define
#define
#define
#define
#define
PARPORT_CONTROL_STROBE
PARPORT_CONTROL_AUTOFD
PARPORT_CONTROL_INIT
PARPORT_CONTROL_SELECT
PARPORT_CONTROL_EN_IRQ
0x1
0x2
0x4
0x8
0x10 /* NOTA: novo! */
#define
#define
#define
#define
#define
PARPORT_STATUS_ERROR
PARPORT_STATUS_SELECT
PARPORT_STATUS_PAPEROUT
PARPORT_STATUS_ACK
PARPORT_STATUS_BUSY
0x8
0x10
0x20
0x40
0x80
Programação de Sistemas
Centronics : 21/33
Interface modo interrupção (3)
char dev_name[] = "Interrupt parport";
struct semaphore byte_rec; /* semáforo para espera de IRQ */
irqreturn_t IRQ_handler(int irq, void *dev_id);
int total_esc,num_int; /* Contador de bytes enviados e total de interrupções */
/* Constantes PCL */
char uel[9] = { '\x1b','%','-','1','2','3','4','5','X' };
char printerReset[2] = { '\x1b','E' };
/* Mantem-se a calha de alimentação */
char paperSource[5] = { '\x1b','&','l','0','H' };
/* Tamanho papel, A4=26 */
char paperSize[6] = { '\x1b','&','l','2','6','A' };
/* Margem de topo 12 linhas */
char printerTop[6] = { '\x1b','&','l','1','2','E' };
/* terminacao linha 2-CR=CR, LF=CR+LF, FF=FF */
char lineTermination[5] = { '\x1b','&','k','2','G' };
/* selecciona símbolos de conjunto PC-8, espaçamento proporcional, altura 14 pt,
estilo direito, espessura negrito, fonte Times */
char fontSet[22] = { '\x1b','(','1','0','U','\x1b','(','s','1','p','1',
'4','v','0','s','3','b','4','1','0','1','T' };
Programação de Sistemas
Centronics : 22/33
Interface modo interrupção (4)
irqreturn_t IRQ_handler(int irq, void *dev_id) {
/* NOTA: nova função, desbloqueia gestor de semáforo */
up(&byte_rec);
num_int++;
return IRQ_HANDLED; }
int init_module(void) {
int result = register_chrdev(MDN,dev_name,&parport_ops);
if (result<0) {
printk(KERN_WARNING "can't get major %d\n",MDN);
return result; }
printk(KERN_INFO "Parport_int installed!\n");
return 0; }
void cleanup_module(void) {
unregister_chrdev(MDN,dev_name);
printk(KERN_INFO "Parport_int removed!\n"); }
Programação de Sistemas
Centronics : 23/33
Interface modo interrupção (5)
int parport_release(struct inode *inode,struct file *filp) {
/* NOTA: libertar IRQ que já não é necessario */
free_irq(IRQ, NULL);
/* desactiva geração de interupção da porta paralela */
outb(PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE |
PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT, BASE+2);
printk(KERN_INFO "Parport_int closed\n Written %d\n interrupts %d\n",
total_esc, num_int);
return 0;
}
Programação de Sistemas
Centronics : 24/33
Interface modo interrupção (6)
int parport_open(struct inode *inode, struct file *filp) {
int result;
/* open device */
printk(KERN_INFO "Parport_int open\n");
total_esc = num_in t= 0;
/* NOTA: Instalar função de tratamento de IRQ */
result= request_irq(IRQ, IRQ_handler, SA_INTERRUPT, dev_name, NULL);
if (result!=0) {
printk(KERN_WARNING "can't get IRQ %d\n",IRQ);
return result; }
Programação de Sistemas
Centronics : 25/33
Interface modo interrupção (7)
/* inicializar impressora na porta paralela */
outb(PARPORT_CONTROL_INIT | PARPORT_CONTROL_SELECT |
PARPORT_CONTROL_AUTOFD, BASE+2);
udelay(5);
outb( 0xff & (~PARPORT_CONTROL_EN_IRQ),BASE+2 );
/* inicializar semáforo bloqueado para esperar chegada da interrupção */
init_MUTEX_LOCKED(&byte_rec);
/* comandos PCL de inicialização da impressora */
parport_write( NULL,&printerReset[0],2,NULL );
parport_write( NULL,&paperSource[0],5,NULL );
parport_write( NULL,&paperSize[0],6,NULL );
parport_write( NULL,&printerTop[0],6,NULL );
parport_write( NULL,&lineTermination[0],5,NULL );
parport_write( NULL,&fontSet[0],22,NULL );
return 0; /* success */ }
Programação de Sistemas
Centronics : 26/33
Interface modo interrupção (8)
ssize_t parport_write(struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
/* Writes buf to the Data port */
char *plocal=buf;
ssize_t wrote=0;
unsigned char status, data;
/* Esperar que a impressora esteja pronta para iniciar impressão
(útil caso a impressora esteja a terminar alguma impressão) */
for (;;) {
status = inb(BASE+1);
status = status & (PARPORT_STATUS_BUSY | PARPORT_STATUS_ERROR);
if ( status == PARPORT_STATUS_ERROR ) break;
udelay(50); }
while(wrote<count) {
/* Set the data lines */
data = *plocal++;
outb(data,BASE);
udelay(1); /* Delay for a bit */
Programação de Sistemas
Centronics : 27/33
Interface modo interrupção (9)
/* Pulse strobe */
outb(PARPORT_CONTROL_EN_IRQ | PARPORT_CONTROL_AUTOFD |
PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT, BASE+2);
udelay(5);
/* End the pulse */
outb(PARPORT_CONTROL_EN_IRQ |PARPORT_CONTROL_AUTOFD |
PARPORT_CONTROL_STROBE |
PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT, BASE+2);
/* A esperar IRQ * /
if ( down_interruptible(&byte_rec)!=0 ) break;
wrote++;
total_esc++;
}
printk(KERN_INFO "Parport_int: Foram escritos %d bytes\n", wrote);
return wrote; }
Programação de Sistemas
Centronics : 28/33
Instalação do controlador (1)
1. Gerar o controlador
[root@manitoba parport]#make –C /lib/modules/`uname-r`/build=M=`pwd` modules
make: Entering directory `/usr/src/kernels/2.6.18-1.2798.fc6-i686'
CC [M] /root/parport/parport_ops.o
/root/parport/parport_ops.c: In function ‘parport_write’:
/root/parport/parport_ops.c: In function ‘init_module’:
/root/parport/parport_ops.c:140: warning: assignment makes integer from pointer
without a cast
Building modules, stage 2.
MODPOST
CC /root/parport/parport_ops.mod.o
LD [M] /root/parport/parport_ops.ko
make: Leaving directory `/usr/src/kernels/2.6.18-1.2798.fc6-i686'
Programação de Sistemas
Centronics : 29/33
Instalação do controlador (2)
2. Criar um i-node
[root@manitoba parport]# mknod /dev/parport_ops c 240 0
3. Inserir o módulo no sistema
[root@manitoba parport]# /sbin/insmod parport_ops.ko
Nota: efeito da função init_module() pode ser
observado no ficheiro /var/log/messages
Mar 29 17:51:54 manitoba kernel: Parport_ops installed!
A instalação pode ser confirmada
– Pelo comando lsmod
Module
Size
parport_ops
Used by
7296
0
– No directório /dev/
[root@manitoba parport]# ls -l /dev/parport_ops
crw-rw-rw- 1 root root 240, 0 Mar 29 14:50
/dev/parport_ops
Programação de Sistemas
Centronics : 30/33
Instalação do controlador (3)
4. Experimentar com o programa
#include <stdio.h>
#define SIZE 128
main(int argc, char **argv) {
int fsA;
FILE *fsB;
int count;
char buf[SIZE];
if (argc!=2) {
fprintf( stderr,"Apenas 1 parametro-ficheiro a despejar\n" );
exit(12); }
fsA = open( "/dev/parport_ops",O_WRONLY );
if(fsA<0) {
perror("");
exit(10); }
fprintf( stderr,"Abri /dev/parport_ops\n" );
Programação de Sistemas
Centronics : 31/33
Instalação do controlador (4)
fsB = fopen( argv[1],"r" );
if(fsB==NULL) {
perror("");
exit(10); }
fprintf( stderr,"Abri %s\n",argv[1 ]);
do {
count = fread(&buf[0],1,SIZE,fsB);
if(count>0) write(fsA,&buf[0],count);
} while (count!=0);
close(fsA); fclose(fsB);
}
Programação de Sistemas
Centronics : 32/33
Instalação do controlador (5)
5. Depois de experimentar, eliminar módulo do sistema
[root@manitoba rgc]# /sbin/rmmod /dev/parport_ops
6. Eliminar referência a dispositivo
[root@manitoba rgc]# rm /dev/parport_ops
rm: remove character special file `/dev/parport_ops'? y
[root@manitoba rgc]#
Programação de Sistemas
Centronics : 33/33
Download

Programação de Sistemas