ser_a2232.c

来自「linux 内核源代码」· C语言 代码 · 共 822 行 · 第 1/2 页

C
822
字号
	status->Command = a2232_cmd | A2232CMD_Open |  A2232CMD_Enable;	status->SoftFlow = softflow;	status->OutDisable = 0;	status->Setup = -1;	local_irq_restore(flags);	return 0;}static int  a2232_chars_in_buffer(void *ptr){	struct a2232_port *port;	volatile struct a2232status *status; 	unsigned char ret; /* we need modulo-256 arithmetics */	port = ptr;	status = a2232stat(port->which_a2232, port->which_port_on_a2232);#if A2232_IOBUFLEN != 256#error "Re-Implement a2232_chars_in_buffer()!"#endif	ret = (status->OutHead - status->OutTail);	return ret;}static void a2232_close(void *ptr){	a2232_disable_tx_interrupts(ptr);	a2232_disable_rx_interrupts(ptr);	/* see the comment in a2232_shutdown_port above. */}static void a2232_hungup(void *ptr){	a2232_close(ptr);}/*** END   OF REAL_DRIVER FUNCTIONS ***//*** BEGIN  FUNCTIONS EXPECTED BY TTY DRIVER STRUCTS ***/static int a2232_ioctl(	struct tty_struct *tty, struct file *file,			unsigned int cmd, unsigned long arg){	return -ENOIOCTLCMD;}static void a2232_throttle(struct tty_struct *tty){/* Throttle: System cannot take another chars: Drop RTS or             send the STOP char or whatever.   The A2232 firmware does RTS/CTS anyway, and XON/XOFF   if switched on. So the only thing we can do at this   layer here is not taking any characters out of the   A2232 buffer any more. */	struct a2232_port *port = (struct a2232_port *) tty->driver_data;	port->throttle_input = -1;}static void a2232_unthrottle(struct tty_struct *tty){/* Unthrottle: dual to "throttle()" above. */	struct a2232_port *port = (struct a2232_port *) tty->driver_data;	port->throttle_input = 0;}static int  a2232_open(struct tty_struct * tty, struct file * filp){/* More or less stolen from other drivers. */	int line;	int retval;	struct a2232_port *port;	line = tty->index;	port = &a2232_ports[line];		tty->driver_data = port;	port->gs.tty = tty;	port->gs.count++;	retval = gs_init_port(&port->gs);	if (retval) {		port->gs.count--;		return retval;	}	port->gs.flags |= GS_ACTIVE;	retval = gs_block_til_ready(port, filp);	if (retval) {		port->gs.count--;		return retval;	}	a2232_enable_rx_interrupts(port);		return 0;}/*** END OF FUNCTIONS EXPECTED BY TTY DRIVER STRUCTS ***/static irqreturn_t a2232_vbl_inter(int irq, void *data){#if A2232_IOBUFLEN != 256#error "Re-Implement a2232_vbl_inter()!"#endifstruct a2232_port *port;volatile struct a2232memory *mem;volatile struct a2232status *status;unsigned char newhead;unsigned char bufpos; /* Must be unsigned char. We need the modulo-256 arithmetics */unsigned char ncd, ocd, ccd; /* names consistent with the NetBSD driver */volatile u_char *ibuf, *cbuf, *obuf;int ch, err, n, p;	for (n = 0; n < nr_a2232; n++){		/* for every completely initialized A2232 board */		mem = a2232mem(n);		for (p = 0; p < NUMLINES; p++){	/* for every port on this board */			err = 0;			port = &a2232_ports[n*NUMLINES+p];			if ( port->gs.flags & GS_ACTIVE ){ /* if the port is used */				status = a2232stat(n,p);				if (!port->disable_rx && !port->throttle_input){ /* If input is not disabled */					newhead = status->InHead;               /* 65EC02 write pointer */					bufpos = status->InTail;					/* check for input for this port */					if (newhead != bufpos) {						/* buffer for input chars/events */						ibuf = mem->InBuf[p]; 						/* data types of bytes in ibuf */						cbuf = mem->InCtl[p]; 						/* do for all chars */						while (bufpos != newhead) {							/* which type of input data? */							switch (cbuf[bufpos]) {								/* switch on input event (CD, BREAK, etc.) */							case A2232INCTL_EVENT:								switch (ibuf[bufpos++]) {								case A2232EVENT_Break:									/* TODO: Handle BREAK signal */									break;									/*	A2232EVENT_CarrierOn and A2232EVENT_CarrierOff are										handled in a separate queue and should not occur here. */								case A2232EVENT_Sync:									printk("A2232: 65EC02 software sent SYNC event, don't know what to do. Ignoring.");									break;								default:									printk("A2232: 65EC02 software broken, unknown event type %d occurred.\n",ibuf[bufpos-1]);								} /* event type switch */								break; 							case A2232INCTL_CHAR:								/* Receive incoming char */								a2232_receive_char(port, ibuf[bufpos], err);								bufpos++;								break; 							default:								printk("A2232: 65EC02 software broken, unknown data type %d occurred.\n",cbuf[bufpos]);								bufpos++;							} /* switch on input data type */						} /* while there's something in the buffer */						status->InTail = bufpos;            /* tell 65EC02 what we've read */											} /* if there was something in the buffer */                          				} /* If input is not disabled */				/* Now check if there's something to output */				obuf = mem->OutBuf[p];				bufpos = status->OutHead;				while ( (port->gs.xmit_cnt > 0)		&&					(!port->gs.tty->stopped)	&&					(!port->gs.tty->hw_stopped) ){	/* While there are chars to transmit */					if (((bufpos+1) & A2232_IOBUFLENMASK) != status->OutTail) { /* If the A2232 buffer is not full */						ch = port->gs.xmit_buf[port->gs.xmit_tail];					/* get the next char to transmit */						port->gs.xmit_tail = (port->gs.xmit_tail+1) & (SERIAL_XMIT_SIZE-1); /* modulo-addition for the gs.xmit_buf ring-buffer */						obuf[bufpos++] = ch;																/* put it into the A2232 buffer */						port->gs.xmit_cnt--;					}					else{																									/* If A2232 the buffer is full */						break;																							/* simply stop filling it. */					}																	}									status->OutHead = bufpos;									/* WakeUp if output buffer runs low */				if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) {					tty_wakeup(port->gs.tty);				}			} // if the port is used		} // for every port on the board					/* Now check the CD message queue */		newhead = mem->Common.CDHead;		bufpos = mem->Common.CDTail;		if (newhead != bufpos){				/* There are CD events in queue */			ocd = mem->Common.CDStatus; 		/* get old status bits */			while (newhead != bufpos){		/* read all events */				ncd = mem->CDBuf[bufpos++]; 	/* get one event */				ccd = ncd ^ ocd; 		/* mask of changed lines */				ocd = ncd; 			/* save new status bits */				for(p=0; p < NUMLINES; p++){	/* for all ports */					if (ccd & 1){		/* this one changed */						struct a2232_port *port = &a2232_ports[n*7+p];						port->cd_status = !(ncd & 1); /* ncd&1 <=> CD is now off */						if (!(port->gs.flags & ASYNC_CHECK_CD))							;	/* Don't report DCD changes */						else if (port->cd_status) { // if DCD on: DCD went UP!														/* Are we blocking in open?*/							wake_up_interruptible(&port->gs.open_wait);						}						else { // if DCD off: DCD went DOWN!							if (port->gs.tty)								tty_hangup (port->gs.tty);						}											} // if CD changed for this port					ccd >>= 1;					ncd >>= 1;									/* Shift bits for next line */				} // for every port			} // while CD events in queue			mem->Common.CDStatus = ocd; /* save new status */			mem->Common.CDTail = bufpos; /* remove events */		} // if events in CD queue			} // for every completely initialized A2232 board	return IRQ_HANDLED;}static void a2232_init_portstructs(void){	struct a2232_port *port;	int i;	for (i = 0; i < MAX_A2232_BOARDS*NUMLINES; i++) {		port = a2232_ports + i;		port->which_a2232 = i/NUMLINES;		port->which_port_on_a2232 = i%NUMLINES;		port->disable_rx = port->throttle_input = port->cd_status = 0;		port->gs.magic = A2232_MAGIC;		port->gs.close_delay = HZ/2;		port->gs.closing_wait = 30 * HZ;		port->gs.rd = &a2232_real_driver;#ifdef NEW_WRITE_LOCKING		init_MUTEX(&(port->gs.port_write_mutex));#endif		init_waitqueue_head(&port->gs.open_wait);		init_waitqueue_head(&port->gs.close_wait);	}}static const struct tty_operations a2232_ops = {	.open = a2232_open,	.close = gs_close,	.write = gs_write,	.put_char = gs_put_char,	.flush_chars = gs_flush_chars,	.write_room = gs_write_room,	.chars_in_buffer = gs_chars_in_buffer,	.flush_buffer = gs_flush_buffer,	.ioctl = a2232_ioctl,	.throttle = a2232_throttle,	.unthrottle = a2232_unthrottle,	.set_termios = gs_set_termios,	.stop = gs_stop,	.start = gs_start,	.hangup = gs_hangup,};static int a2232_init_drivers(void){	int error;	a2232_driver = alloc_tty_driver(NUMLINES * nr_a2232);	if (!a2232_driver)		return -ENOMEM;	a2232_driver->owner = THIS_MODULE;	a2232_driver->driver_name = "commodore_a2232";	a2232_driver->name = "ttyY";	a2232_driver->major = A2232_NORMAL_MAJOR;	a2232_driver->type = TTY_DRIVER_TYPE_SERIAL;	a2232_driver->subtype = SERIAL_TYPE_NORMAL;	a2232_driver->init_termios = tty_std_termios;	a2232_driver->init_termios.c_cflag =		B9600 | CS8 | CREAD | HUPCL | CLOCAL;	a2232_driver->init_termios.c_ispeed = 9600;	a2232_driver->init_termios.c_ospeed = 9600;	a2232_driver->flags = TTY_DRIVER_REAL_RAW;	tty_set_operations(a2232_driver, &a2232_ops);	if ((error = tty_register_driver(a2232_driver))) {		printk(KERN_ERR "A2232: Couldn't register A2232 driver, error = %d\n",		       error);		put_tty_driver(a2232_driver);		return 1;	}	return 0;}static int __init a2232board_init(void){	struct zorro_dev *z;	unsigned int boardaddr;	int bcount;	short start;	u_char *from;	volatile u_char *to;	volatile struct a2232memory *mem;#ifdef CONFIG_SMP	return -ENODEV;	/* This driver is not SMP aware. Is there an SMP ZorroII-bus-machine? */#endif	if (!MACH_IS_AMIGA){		return -ENODEV;	}	printk("Commodore A2232 driver initializing.\n"); /* Say that we're alive. */	z = NULL;	nr_a2232 = 0;	while ( (z = zorro_find_device(ZORRO_WILDCARD, z)) ){		if (	(z->id != ZORRO_PROD_CBM_A2232_PROTOTYPE) && 			(z->id != ZORRO_PROD_CBM_A2232)	){			continue;	// The board found was no A2232		}		if (!zorro_request_device(z,"A2232 driver"))			continue;		printk("Commodore A2232 found (#%d).\n",nr_a2232);		zd_a2232[nr_a2232] = z;		boardaddr = ZTWO_VADDR( z->resource.start );		printk("Board is located at address 0x%x, size is 0x%x.\n", boardaddr, (unsigned int) ((z->resource.end+1) - (z->resource.start)));		mem = (volatile struct a2232memory *) boardaddr;		(void) mem->Enable6502Reset;   /* copy the code across to the board */		to = (u_char *)mem;  from = a2232_65EC02code; bcount = sizeof(a2232_65EC02code) - 2;		start = *(short *)from;		from += sizeof(start);		to += start;		while(bcount--) *to++ = *from++;		printk("65EC02 software uploaded to the A2232 memory.\n");  		mem->Common.Crystal = A2232_UNKNOWN;  /* use automatic speed check */  		/* start 6502 running */		(void) mem->ResetBoard;		printk("A2232's 65EC02 CPU up and running.\n");  		/* wait until speed detector has finished */		for (bcount = 0; bcount < 2000; bcount++) {			udelay(1000);			if (mem->Common.Crystal)				break;		}		printk((mem->Common.Crystal?"A2232 oscillator crystal detected by 65EC02 software: ":"65EC02 software could not determine A2232 oscillator crystal: "));		switch (mem->Common.Crystal){		case A2232_UNKNOWN:			printk("Unknown crystal.\n");			break; 		case A2232_NORMAL:			printk ("Normal crystal.\n");			break;		case A2232_TURBO:			printk ("Turbo crystal.\n");			break;		default:			printk ("0x%x. Huh?\n",mem->Common.Crystal);		}		nr_a2232++;	}		printk("Total: %d A2232 boards initialized.\n", nr_a2232); /* Some status report if no card was found */	a2232_init_portstructs();	/*		a2232_init_drivers also registers the drivers. Must be here because all boards		have to be detected first.	*/	if (a2232_init_drivers()) return -ENODEV; // maybe we should use a different -Exxx?	request_irq(IRQ_AMIGA_VERTB, a2232_vbl_inter, 0, "A2232 serial VBL", a2232_driver_ID);	return 0;}static void __exit a2232board_exit(void){	int i;	for (i = 0; i < nr_a2232; i++) {		zorro_release_device(zd_a2232[i]);	}	tty_unregister_driver(a2232_driver);	put_tty_driver(a2232_driver);	free_irq(IRQ_AMIGA_VERTB, a2232_driver_ID);}module_init(a2232board_init);module_exit(a2232board_exit);MODULE_AUTHOR("Enver Haase");MODULE_DESCRIPTION("Amiga A2232 multi-serial board driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?