Annotation of sys/dev/sbus/magma.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: magma.c,v 1.15 2005/07/09 22:23:15 miod Exp $ */
2: /*
3: * magma.c
4: *
5: * Copyright (c) 1998 Iain Hibbert
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by Iain Hibbert
19: * 4. The name of the author may not be used to endorse or promote products
20: * derived from this software without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32: *
33: #define MAGMA_DEBUG
34: */
35:
36: /*
37: * Driver for Magma SBus Serial/Parallel cards using the Cirrus Logic
38: * CD1400 & CD1190 chips
39: */
40:
41: #include <sys/param.h>
42: #include <sys/systm.h>
43: #include <sys/proc.h>
44: #include <sys/device.h>
45: #include <sys/file.h>
46: #include <sys/ioctl.h>
47: #include <sys/malloc.h>
48: #include <sys/tty.h>
49: #include <sys/time.h>
50: #include <sys/kernel.h>
51: #include <sys/syslog.h>
52: #include <sys/conf.h>
53: #include <sys/errno.h>
54:
55: #include <machine/autoconf.h>
56: #include <machine/conf.h>
57: #include <machine/bus.h>
58: #include <machine/bppioctl.h>
59:
60: #include <dev/sbus/sbusvar.h>
61: #include <dev/ic/cd1400reg.h>
62: #include <dev/ic/cd1190reg.h>
63:
64: #include <dev/sbus/magmareg.h>
65:
66: /* supported cards
67: *
68: * The table below lists the cards that this driver is likely to
69: * be able to support.
70: *
71: * Cards with parallel ports: except for the LC2+1Sp, they all use
72: * the CD1190 chip which I know nothing about. I've tried to leave
73: * hooks for it so it shouldn't be too hard to add support later.
74: * (I think somebody is working on this separately)
75: *
76: * Thanks to Bruce at Magma for telling me the hardware offsets.
77: */
78: static const struct magma_board_info supported_cards[] = {
79: {
80: "MAGMA_Sp", "MAGMA,4_Sp", "Magma 4 Sp", 4, 0,
81: 1, 0xa000, 0xc000, 0xe000, { 0x8000, 0, 0, 0 },
82: 0, { 0, 0 }
83: },
84: {
85: "MAGMA_Sp", "MAGMA,8_Sp", "Magma 8 Sp", 8, 0,
86: 2, 0xa000, 0xc000, 0xe000, { 0x4000, 0x6000, 0, 0 },
87: 0, { 0, 0 }
88: },
89: {
90: "MAGMA_Sp", "MAGMA,_8HS_Sp", "Magma Fast 8 Sp", 8, 0,
91: 2, 0x2000, 0x4000, 0x6000, { 0x8000, 0xa000, 0, 0 },
92: 0, { 0, 0 }
93: },
94: {
95: "MAGMA_Sp", "MAGMA,_8SP_422", "Magma 8 Sp - 422", 8, 0,
96: 2, 0x2000, 0x4000, 0x6000, { 0x8000, 0xa000, 0, 0 },
97: 0, { 0, 0 }
98: },
99: {
100: "MAGMA_Sp", "MAGMA,12_Sp", "Magma 12 Sp", 12, 0,
101: 3, 0xa000, 0xc000, 0xe000, { 0x2000, 0x4000, 0x6000, 0 },
102: 0, { 0, 0 }
103: },
104: {
105: "MAGMA_Sp", "MAGMA,16_Sp", "Magma 16 Sp", 16, 0,
106: 4, 0xd000, 0xe000, 0xf000, { 0x8000, 0x9000, 0xa000, 0xb000 },
107: 0, { 0, 0 }
108: },
109: {
110: "MAGMA_Sp", "MAGMA,16_Sp_2", "Magma 16 Sp", 16, 0,
111: 4, 0x2000, 0x4000, 0x6000, { 0x8000, 0xa000, 0xc000, 0xe000 },
112: 0, { 0, 0 }
113: },
114: {
115: "MAGMA_Sp", "MAGMA,16HS_Sp", "Magma Fast 16 Sp", 16, 0,
116: 4, 0x2000, 0x4000, 0x6000, { 0x8000, 0xa000, 0xc000, 0xe000 },
117: 0, { 0, 0 }
118: },
119: {
120: "MAGMA_Sp", "MAGMA,21_Sp", "Magma LC 2+1 Sp", 2, 1,
121: 1, 0xa000, 0xc000, 0xe000, { 0x8000, 0, 0, 0 },
122: 0, { 0, 0 }
123: },
124: {
125: "MAGMA_Sp", "MAGMA,21HS_Sp", "Magma 2+1 Sp", 2, 1,
126: 1, 0xa000, 0xc000, 0xe000, { 0x4000, 0, 0, 0 },
127: 1, { 0x6000, 0 }
128: },
129: {
130: "MAGMA_Sp", "MAGMA,41_Sp", "Magma 4+1 Sp", 4, 1,
131: 1, 0xa000, 0xc000, 0xe000, { 0x4000, 0, 0, 0 },
132: 1, { 0x6000, 0 }
133: },
134: {
135: "MAGMA_Sp", "MAGMA,82_Sp", "Magma 8+2 Sp", 8, 2,
136: 2, 0xd000, 0xe000, 0xf000, { 0x8000, 0x9000, 0, 0 },
137: 2, { 0xa000, 0xb000 }
138: },
139: {
140: "MAGMA_Sp", "MAGMA,P1_Sp", "Magma P1 Sp", 0, 1,
141: 0, 0, 0, 0, { 0, 0, 0, 0 },
142: 1, { 0x8000, 0 }
143: },
144: {
145: "MAGMA_Sp", "MAGMA,P2_Sp", "Magma P2 Sp", 0, 2,
146: 0, 0, 0, 0, { 0, 0, 0, 0 },
147: 2, { 0x4000, 0x8000 }
148: },
149: {
150: "MAGMA 2+1HS Sp", "", "Magma 2+1HS Sp", 2, 0,
151: 1, 0xa000, 0xc000, 0xe000, { 0x4000, 0, 0, 0 },
152: 1, { 0x8000, 0 }
153: },
154: {
155: NULL, NULL, NULL, 0, 0,
156: 0, 0, 0, 0, { 0, 0, 0, 0 },
157: 0, { 0, 0 }
158: }
159: };
160:
161: /************************************************************************
162: *
163: * Autoconfig Stuff
164: */
165:
166: struct cfattach magma_ca = {
167: sizeof(struct magma_softc), magma_match, magma_attach
168: };
169:
170: struct cfdriver magma_cd = {
171: NULL, "magma", DV_DULL
172: };
173:
174: struct cfattach mtty_ca = {
175: sizeof(struct mtty_softc), mtty_match, mtty_attach
176: };
177:
178: struct cfdriver mtty_cd = {
179: NULL, "mtty", DV_TTY
180: };
181:
182: struct cfattach mbpp_ca = {
183: sizeof(struct mbpp_softc), mbpp_match, mbpp_attach
184: };
185:
186: struct cfdriver mbpp_cd = {
187: NULL, "mbpp", DV_DULL
188: };
189:
190: /************************************************************************
191: *
192: * CD1400 Routines
193: *
194: * cd1400_compute_baud calculate COR/BPR register values
195: * cd1400_write_ccr write a value to CD1400 ccr
196: * cd1400_read_reg read from a CD1400 register
197: * cd1400_write_reg write to a CD1400 register
198: * cd1400_enable_transmitter enable transmitting on CD1400 channel
199: */
200:
201: /*
202: * compute the bpr/cor pair for any baud rate
203: * returns 0 for success, 1 for failure
204: */
205: int
206: cd1400_compute_baud(speed_t speed, int clock, int *cor, int *bpr)
207: {
208: int c, co, br;
209:
210: if (speed < 50 || speed > 150000)
211: return (1);
212:
213: for (c = 0, co = 8 ; co <= 2048 ; co <<= 2, c++) {
214: br = ((clock * 1000000) + (co * speed) / 2) / (co * speed);
215: if (br < 0x100) {
216: *bpr = br;
217: *cor = c;
218: return (0);
219: }
220: }
221:
222: return (1);
223: }
224:
225: #define CD1400_READ_REG(cd,reg) \
226: bus_space_read_1((cd)->cd_regt, (cd)->cd_regh, (reg))
227: #define CD1400_WRITE_REG(cd,reg,value) \
228: bus_space_write_1((cd)->cd_regt, (cd)->cd_regh, (reg), (value))
229:
230: /*
231: * Write a CD1400 channel command, should have a timeout?
232: */
233: __inline void
234: cd1400_write_ccr(struct cd1400 *cd, u_char cmd)
235: {
236: while (CD1400_READ_REG(cd, CD1400_CCR))
237: /*EMPTY*/;
238:
239: CD1400_WRITE_REG(cd, CD1400_CCR, cmd);
240: }
241:
242: /*
243: * enable transmit service requests for cd1400 channel
244: */
245: void
246: cd1400_enable_transmitter(struct cd1400 *cd, int channel)
247: {
248: int s, srer;
249:
250: s = spltty();
251: CD1400_WRITE_REG(cd, CD1400_CAR, channel);
252: srer = CD1400_READ_REG(cd, CD1400_SRER);
253: SET(srer, CD1400_SRER_TXRDY);
254: CD1400_WRITE_REG(cd, CD1400_SRER, srer);
255: splx(s);
256: }
257:
258: /************************************************************************
259: *
260: * CD1190 Routines
261: */
262:
263: /* well, there are none yet */
264:
265: /************************************************************************
266: *
267: * Magma Routines
268: *
269: * magma_match reports if we have a magma board available
270: * magma_attach attaches magma boards to the sbus
271: * magma_hard hardware level interrupt routine
272: * magma_soft software level interrupt routine
273: */
274:
275: int
276: magma_match(struct device *parent, void *vcf, void *aux)
277: {
278: struct sbus_attach_args *sa = aux;
279: const struct magma_board_info *card;
280:
281: /* See if we support this device */
282: for (card = supported_cards; ; card++) {
283: if (card->mb_sbusname == NULL)
284: /* End of table: no match */
285: return (0);
286: if (strcmp(sa->sa_name, card->mb_sbusname) == 0)
287: break;
288: }
289: return (1);
290: }
291:
292: void
293: magma_attach(struct device *parent, struct device *dev, void *aux)
294: {
295: struct sbus_attach_args *sa = aux;
296: struct magma_softc *sc = (struct magma_softc *)dev;
297: const struct magma_board_info *card;
298: char magma_prom[40], *clockstr;
299: int chip, cd_clock;
300:
301: getpropstringA(sa->sa_node, "magma_prom", magma_prom);
302: for (card = supported_cards; card->mb_name != NULL; card++) {
303: if (strcmp(sa->sa_name, card->mb_sbusname) != 0)
304: continue;
305: if (strcmp(magma_prom, card->mb_name) == 0)
306: break;
307: }
308: if (card->mb_name == NULL) {
309: printf(": %s (unsupported)\n", magma_prom);
310: return;
311: }
312:
313: sc->sc_bustag = sa->sa_bustag;
314:
315: clockstr = getpropstring(sa->sa_node, "clock");
316: if (strlen(clockstr) == 0)
317: cd_clock = 25;
318: else {
319: cd_clock = 0;
320: while (*clockstr != '\0')
321: cd_clock = cd_clock * 10 + *clockstr++ - '0';
322: }
323:
324: if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
325: sa->sa_reg[0].sbr_offset, sa->sa_reg[0].sbr_size,
326: 0, 0, &sc->sc_iohandle) != 0) {
327: printf(": can't map registers\n");
328: return;
329: }
330:
331: if (sa->sa_nintr < 1) {
332: printf(": can't find interrupt\n");
333: return;
334: }
335: sc->sc_ih = bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_TTY, 0,
336: magma_hard, sc, dev->dv_xname);
337: if (sc->sc_ih == NULL) {
338: printf(": couldn't establish interrupt, pri %d\n",
339: INTLEV(sa->sa_pri));
340: bus_space_unmap(sc->sc_bustag, sc->sc_iohandle,
341: sa->sa_reg[0].sbr_size);
342: return;
343: }
344:
345: sc->sc_sih = softintr_establish(IPL_TTY, magma_soft, sc);
346: if (sc->sc_sih == NULL) {
347: printf(": can't get soft intr\n");
348: bus_space_unmap(sc->sc_bustag, sc->sc_iohandle,
349: sa->sa_reg[0].sbr_size);
350: return;
351: }
352:
353: printf(": %s\n", card->mb_realname);
354:
355: sc->ms_board = card;
356: sc->ms_ncd1400 = card->mb_ncd1400;
357: sc->ms_ncd1190 = card->mb_ncd1190;
358:
359: /* the SVCACK* lines are daisychained */
360: if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle,
361: card->mb_svcackr, 1, &sc->sc_svcackrh)) {
362: printf(": failed to map svcackr\n");
363: return;
364: }
365: if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle,
366: card->mb_svcackt, 1, &sc->sc_svcackth)) {
367: printf(": failed to map svcackt\n");
368: return;
369: }
370: if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle,
371: card->mb_svcackm, 1, &sc->sc_svcackmh)) {
372: printf(": failed to map svcackm\n");
373: return;
374: }
375:
376: /* init the cd1400 chips */
377: for (chip = 0 ; chip < card->mb_ncd1400 ; chip++) {
378: struct cd1400 *cd = &sc->ms_cd1400[chip];
379:
380: cd->cd_clock = cd_clock;
381:
382: if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle,
383: card->mb_cd1400[chip], CD1400_REGMAPSIZE, &cd->cd_regh)) {
384: printf(": failed to map cd1400 regs\n");
385: return;
386: }
387: cd->cd_regt = sc->sc_bustag;
388:
389: /* getpropstring(sa->sa_node, "chiprev"); */
390: /* seemingly the Magma drivers just ignore the propstring */
391: cd->cd_chiprev = CD1400_READ_REG(cd, CD1400_GFRCR);
392:
393: dprintf(("%s attach CD1400 %d addr 0x%x rev %x clock %dMHz\n",
394: sc->ms_dev.dv_xname, chip, cd->cd_reg,
395: cd->cd_chiprev, cd->cd_clock));
396:
397: /* clear GFRCR */
398: CD1400_WRITE_REG(cd, CD1400_GFRCR, 0x00);
399:
400: /* reset whole chip */
401: cd1400_write_ccr(cd,
402: CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);
403:
404: /* wait for revision code to be restored */
405: while (CD1400_READ_REG(cd, CD1400_GFRCR) != cd->cd_chiprev)
406: ;
407:
408: /* set the Prescaler Period Register to tick at 1ms */
409: CD1400_WRITE_REG(cd, CD1400_PPR,
410: ((cd->cd_clock * 1000000 / CD1400_PPR_PRESCALER + 500)
411: / 1000));
412:
413: /*
414: * The LC2+1Sp card is the only card that doesn't have a
415: * CD1190 for the parallel port, but uses channel 0 of the
416: * CD1400, so we make a note of it for later and set up the
417: * CD1400 for parallel mode operation.
418: */
419: if (card->mb_npar && card->mb_ncd1190 == 0) {
420: CD1400_WRITE_REG(cd, CD1400_GCR, CD1400_GCR_PARALLEL);
421: cd->cd_parmode = 1;
422: }
423: }
424:
425: /* init the cd1190 chips */
426: for (chip = 0 ; chip < card->mb_ncd1190 ; chip++) {
427: struct cd1190 *cd = &sc->ms_cd1190[chip];
428:
429: if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle,
430: card->mb_cd1190[chip], CD1190_REGMAPSIZE, &cd->cd_regh)) {
431: printf(": failed to map cd1190 regs\n");
432: return;
433: }
434: cd->cd_regt = sc->sc_bustag;
435: dprintf(("%s attach CD1190 %d addr 0x%x (failed)\n",
436: sc->ms_dev.dv_xname, chip, cd->cd_reg));
437: /* XXX don't know anything about these chips yet */
438: }
439:
440: /* configure the children */
441: (void)config_found(dev, mtty_match, NULL);
442: (void)config_found(dev, mbpp_match, NULL);
443: }
444:
445: /*
446: * hard interrupt routine
447: *
448: * returns 1 if it handled it, otherwise 0
449: *
450: * runs at interrupt priority
451: */
452: int
453: magma_hard(void *arg)
454: {
455: struct magma_softc *sc = arg;
456: struct cd1400 *cd;
457: int chip, status = 0;
458: int serviced = 0;
459: int needsoftint = 0;
460:
461: /*
462: * check status of all the CD1400 chips
463: */
464: for (chip = 0 ; chip < sc->ms_ncd1400 ; chip++)
465: status |= CD1400_READ_REG(&sc->ms_cd1400[chip], CD1400_SVRR);
466:
467: if (ISSET(status, CD1400_SVRR_RXRDY)) {
468: /* enter rx service context */
469: u_int8_t rivr = bus_space_read_1(sc->sc_bustag, sc->sc_svcackrh, 0);
470: int port = rivr >> 4;
471:
472: if (rivr & (1<<3)) { /* parallel port */
473: struct mbpp_port *mbpp;
474: int n_chars;
475:
476: mbpp = &sc->ms_mbpp->ms_port[port];
477: cd = mbpp->mp_cd1400;
478:
479: /* don't think we have to handle exceptions */
480: n_chars = CD1400_READ_REG(cd, CD1400_RDCR);
481: while (n_chars--) {
482: if (mbpp->mp_cnt == 0) {
483: SET(mbpp->mp_flags, MBPPF_WAKEUP);
484: needsoftint = 1;
485: break;
486: }
487: *mbpp->mp_ptr = CD1400_READ_REG(cd, CD1400_RDSR);
488: mbpp->mp_ptr++;
489: mbpp->mp_cnt--;
490: }
491: } else { /* serial port */
492: struct mtty_port *mtty;
493: u_char *ptr, n_chars, line_stat;
494:
495: mtty = &sc->ms_mtty->ms_port[port];
496: cd = mtty->mp_cd1400;
497:
498: if (ISSET(rivr, CD1400_RIVR_EXCEPTION)) {
499: line_stat = CD1400_READ_REG(cd, CD1400_RDSR);
500: n_chars = 1;
501: } else { /* no exception, received data OK */
502: line_stat = 0;
503: n_chars = CD1400_READ_REG(cd, CD1400_RDCR);
504: }
505:
506: ptr = mtty->mp_rput;
507: while (n_chars--) {
508: *ptr++ = line_stat;
509: *ptr++ = CD1400_READ_REG(cd, CD1400_RDSR);
510: if (ptr == mtty->mp_rend)
511: ptr = mtty->mp_rbuf;
512: if (ptr == mtty->mp_rget) {
513: if (ptr == mtty->mp_rbuf)
514: ptr = mtty->mp_rend;
515: ptr -= 2;
516: SET(mtty->mp_flags,
517: MTTYF_RING_OVERFLOW);
518: break;
519: }
520: }
521: mtty->mp_rput = ptr;
522:
523: needsoftint = 1;
524: }
525:
526: CD1400_WRITE_REG(cd, CD1400_EOSRR, 0); /* end service context */
527: serviced = 1;
528: } /* if(rx_service...) */
529:
530: if (ISSET(status, CD1400_SVRR_MDMCH)) {
531: u_int8_t mivr = bus_space_read_1(sc->sc_bustag, sc->sc_svcackmh, 0);
532: int port = mivr >> 4;
533: struct mtty_port *mtty;
534: int carrier;
535: u_char msvr;
536:
537: /*
538: * Handle CD (LC2+1Sp = DSR) changes.
539: */
540: mtty = &sc->ms_mtty->ms_port[port];
541: cd = mtty->mp_cd1400;
542: msvr = CD1400_READ_REG(cd, CD1400_MSVR2);
543: carrier = ISSET(msvr, cd->cd_parmode ? CD1400_MSVR2_DSR : CD1400_MSVR2_CD);
544:
545: if (mtty->mp_carrier != carrier) {
546: SET(mtty->mp_flags, MTTYF_CARRIER_CHANGED);
547: mtty->mp_carrier = carrier;
548: needsoftint = 1;
549: }
550:
551: CD1400_WRITE_REG(cd, CD1400_EOSRR, 0); /* end service context */
552: serviced = 1;
553: } /* if(mdm_service...) */
554:
555: if (ISSET(status, CD1400_SVRR_TXRDY)) {
556: /* enter tx service context */
557: u_int8_t tivr = bus_space_read_1(sc->sc_bustag, sc->sc_svcackth, 0);
558: int port = tivr >> 4;
559:
560: if (tivr & (1<<3)) { /* parallel port */
561: struct mbpp_port *mbpp;
562:
563: mbpp = &sc->ms_mbpp->ms_port[port];
564: cd = mbpp->mp_cd1400;
565:
566: if (mbpp->mp_cnt) {
567: int count = 0;
568:
569: /* fill the fifo */
570: while (mbpp->mp_cnt && count++ < CD1400_PAR_FIFO_SIZE) {
571: CD1400_WRITE_REG(cd, CD1400_TDR, *mbpp->mp_ptr);
572: mbpp->mp_ptr++;
573: mbpp->mp_cnt--;
574: }
575: } else {
576: /* fifo is empty and we got no more data to send, so shut
577: * off interrupts and signal for a wakeup, which can't be
578: * done here in case we beat mbpp_send to the tsleep call
579: * (we are running at >spltty)
580: */
581: CD1400_WRITE_REG(cd, CD1400_SRER, 0);
582: SET(mbpp->mp_flags, MBPPF_WAKEUP);
583: needsoftint = 1;
584: }
585: } else { /* serial port */
586: struct mtty_port *mtty;
587: struct tty *tp;
588:
589: mtty = &sc->ms_mtty->ms_port[port];
590: cd = mtty->mp_cd1400;
591: tp = mtty->mp_tty;
592:
593: if (!ISSET(mtty->mp_flags, MTTYF_STOP)) {
594: int count = 0;
595:
596: /* check if we should start/stop a break */
597: if (ISSET(mtty->mp_flags, MTTYF_SET_BREAK)) {
598: CD1400_WRITE_REG(cd, CD1400_TDR, 0);
599: CD1400_WRITE_REG(cd, CD1400_TDR, 0x81);
600: /* should we delay too? */
601: CLR(mtty->mp_flags, MTTYF_SET_BREAK);
602: count += 2;
603: }
604:
605: if (ISSET(mtty->mp_flags, MTTYF_CLR_BREAK)) {
606: CD1400_WRITE_REG(cd, CD1400_TDR, 0);
607: CD1400_WRITE_REG(cd, CD1400_TDR, 0x83);
608: CLR(mtty->mp_flags, MTTYF_CLR_BREAK);
609: count += 2;
610: }
611:
612: /* I don't quite fill the fifo in case the last one is a
613: * NULL which I have to double up because its the escape
614: * code for embedded transmit characters.
615: */
616: while (mtty->mp_txc > 0 && count < CD1400_TX_FIFO_SIZE - 1) {
617: u_char ch;
618:
619: ch = *mtty->mp_txp;
620:
621: mtty->mp_txc--;
622: mtty->mp_txp++;
623:
624: if (ch == 0) {
625: CD1400_WRITE_REG(cd, CD1400_TDR, ch);
626: count++;
627: }
628:
629: CD1400_WRITE_REG(cd, CD1400_TDR, ch);
630: count++;
631: }
632: }
633:
634: /* if we ran out of work or are requested to STOP then
635: * shut off the txrdy interrupts and signal DONE to flush
636: * out the chars we have sent.
637: */
638: if (mtty->mp_txc == 0 || ISSET(mtty->mp_flags, MTTYF_STOP)) {
639: int srer;
640:
641: srer = CD1400_READ_REG(cd, CD1400_SRER);
642: CLR(srer, CD1400_SRER_TXRDY);
643: CD1400_WRITE_REG(cd, CD1400_SRER, srer);
644: CLR(mtty->mp_flags, MTTYF_STOP);
645:
646: SET(mtty->mp_flags, MTTYF_DONE);
647: needsoftint = 1;
648: }
649: }
650:
651: CD1400_WRITE_REG(cd, CD1400_EOSRR, 0); /* end service context */
652: serviced = 1;
653: } /* if(tx_service...) */
654:
655: /* XXX service CD1190 interrupts too
656: for (chip = 0 ; chip < sc->ms_ncd1190 ; chip++) {
657: }
658: */
659:
660: if (needsoftint)
661: softintr_schedule(sc->sc_sih);
662:
663: return (serviced);
664: }
665:
666: /*
667: * magma soft interrupt handler
668: *
669: * returns 1 if it handled it, 0 otherwise
670: *
671: * runs at spltty()
672: */
673: void
674: magma_soft(void *arg)
675: {
676: struct magma_softc *sc = arg;
677: struct mtty_softc *mtty = sc->ms_mtty;
678: struct mbpp_softc *mbpp = sc->ms_mbpp;
679: int port;
680: int serviced = 0;
681: int s, flags;
682:
683: /*
684: * check the tty ports (if any) to see what needs doing
685: */
686: if (mtty) {
687: for (port = 0 ; port < mtty->ms_nports ; port++) {
688: struct mtty_port *mp = &mtty->ms_port[port];
689: struct tty *tp = mp->mp_tty;
690:
691: if (!ISSET(tp->t_state, TS_ISOPEN))
692: continue;
693:
694: /*
695: * handle any received data
696: */
697: while (mp->mp_rget != mp->mp_rput) {
698: u_char stat;
699: int data;
700:
701: stat = mp->mp_rget[0];
702: data = mp->mp_rget[1];
703: mp->mp_rget = ((mp->mp_rget + 2) == mp->mp_rend) ? mp->mp_rbuf : (mp->mp_rget + 2);
704:
705: if (stat & (CD1400_RDSR_BREAK | CD1400_RDSR_FE))
706: data |= TTY_FE;
707: if (stat & CD1400_RDSR_PE)
708: data |= TTY_PE;
709:
710: if (stat & CD1400_RDSR_OE)
711: log(LOG_WARNING, "%s%x: fifo overflow\n", mtty->ms_dev.dv_xname, port);
712:
713: (*linesw[tp->t_line].l_rint)(data, tp);
714: serviced = 1;
715: }
716:
717: s = splhigh(); /* block out hard interrupt routine */
718: flags = mp->mp_flags;
719: CLR(mp->mp_flags, MTTYF_DONE | MTTYF_CARRIER_CHANGED | MTTYF_RING_OVERFLOW);
720: splx(s); /* ok */
721:
722: if (ISSET(flags, MTTYF_CARRIER_CHANGED)) {
723: dprintf(("%s%x: cd %s\n", mtty->ms_dev.dv_xname, port, mp->mp_carrier ? "on" : "off"));
724: (*linesw[tp->t_line].l_modem)(tp, mp->mp_carrier);
725: serviced = 1;
726: }
727:
728: if (ISSET(flags, MTTYF_RING_OVERFLOW)) {
729: log(LOG_WARNING, "%s%x: ring buffer overflow\n", mtty->ms_dev.dv_xname, port);
730: serviced = 1;
731: }
732:
733: if (ISSET(flags, MTTYF_DONE)) {
734: ndflush(&tp->t_outq, mp->mp_txp - tp->t_outq.c_cf);
735: CLR(tp->t_state, TS_BUSY);
736: (*linesw[tp->t_line].l_start)(tp); /* might be some more */
737: serviced = 1;
738: }
739: } /* for (each mtty...) */
740: }
741:
742: /*
743: * check the bpp ports (if any) to see what needs doing
744: */
745: if (mbpp) {
746: for (port = 0 ; port < mbpp->ms_nports ; port++) {
747: struct mbpp_port *mp = &mbpp->ms_port[port];
748:
749: if (!ISSET(mp->mp_flags, MBPPF_OPEN))
750: continue;
751:
752: s = splhigh(); /* block out hard intr routine */
753: flags = mp->mp_flags;
754: CLR(mp->mp_flags, MBPPF_WAKEUP);
755: splx(s);
756:
757: if (ISSET(flags, MBPPF_WAKEUP)) {
758: wakeup(mp);
759: serviced = 1;
760: }
761: } /* for (each mbpp...) */
762: }
763: }
764:
765: /************************************************************************
766: *
767: * MTTY Routines
768: *
769: * mtty_match match one mtty device
770: * mtty_attach attach mtty devices
771: * mttyopen open mtty device
772: * mttyclose close mtty device
773: * mttyread read from mtty
774: * mttywrite write to mtty
775: * mttyioctl do ioctl on mtty
776: * mttytty return tty pointer for mtty
777: * mttystop stop mtty device
778: * mtty_start start mtty device
779: * mtty_param set mtty parameters
780: * mtty_modem_control set modem control lines
781: */
782:
783: int
784: mtty_match(struct device *parent, void *vcf, void *args)
785: {
786: struct magma_softc *sc = (struct magma_softc *)parent;
787:
788: return (args == mtty_match && sc->ms_board->mb_nser &&
789: sc->ms_mtty == NULL);
790: }
791:
792: void
793: mtty_attach(struct device *parent, struct device *dev, void *args)
794: {
795: struct magma_softc *sc = (struct magma_softc *)parent;
796: struct mtty_softc *ms = (struct mtty_softc *)dev;
797: int port, chip, chan;
798:
799: sc->ms_mtty = ms;
800: dprintf((" addr 0x%x", ms));
801:
802: for (port = 0, chip = 0, chan = 0;
803: port < sc->ms_board->mb_nser; port++) {
804: struct mtty_port *mp = &ms->ms_port[port];
805: struct tty *tp;
806:
807: mp->mp_cd1400 = &sc->ms_cd1400[chip];
808: if (mp->mp_cd1400->cd_parmode && chan == 0) {
809: /* skip channel 0 if parmode */
810: chan = 1;
811: }
812: mp->mp_channel = chan;
813:
814: tp = ttymalloc();
815: tp->t_oproc = mtty_start;
816: tp->t_param = mtty_param;
817:
818: mp->mp_tty = tp;
819:
820: mp->mp_rbuf = malloc(MTTY_RBUF_SIZE, M_DEVBUF, M_NOWAIT);
821: if (mp->mp_rbuf == NULL)
822: break;
823:
824: mp->mp_rend = mp->mp_rbuf + MTTY_RBUF_SIZE;
825:
826: chan = (chan + 1) % CD1400_NO_OF_CHANNELS;
827: if (chan == 0)
828: chip++;
829: }
830:
831: ms->ms_nports = port;
832: printf(": %d tty%s\n", port, port == 1 ? "" : "s");
833: }
834:
835: /*
836: * open routine. returns zero if successful, else error code
837: */
838: int
839: mttyopen(dev_t dev, int flags, int mode, struct proc *p)
840: {
841: int card = MAGMA_CARD(dev);
842: int port = MAGMA_PORT(dev);
843: struct mtty_softc *ms;
844: struct mtty_port *mp;
845: struct tty *tp;
846: struct cd1400 *cd;
847: int s;
848:
849: if (card >= mtty_cd.cd_ndevs || (ms = mtty_cd.cd_devs[card]) == NULL
850: || port >= ms->ms_nports)
851: return (ENXIO); /* device not configured */
852:
853: mp = &ms->ms_port[port];
854: tp = mp->mp_tty;
855: tp->t_dev = dev;
856:
857: if (!ISSET(tp->t_state, TS_ISOPEN)) {
858: SET(tp->t_state, TS_WOPEN);
859:
860: /* set defaults */
861: ttychars(tp);
862: tp->t_iflag = TTYDEF_IFLAG;
863: tp->t_oflag = TTYDEF_OFLAG;
864: tp->t_cflag = TTYDEF_CFLAG;
865: if (ISSET(mp->mp_openflags, TIOCFLAG_CLOCAL))
866: SET(tp->t_cflag, CLOCAL);
867: if (ISSET(mp->mp_openflags, TIOCFLAG_CRTSCTS))
868: SET(tp->t_cflag, CRTSCTS);
869: if (ISSET(mp->mp_openflags, TIOCFLAG_MDMBUF))
870: SET(tp->t_cflag, MDMBUF);
871: tp->t_lflag = TTYDEF_LFLAG;
872: tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
873:
874: /* init ring buffer */
875: mp->mp_rput = mp->mp_rget = mp->mp_rbuf;
876:
877: s = spltty();
878:
879: /* reset CD1400 channel */
880: cd = mp->mp_cd1400;
881: CD1400_WRITE_REG(cd, CD1400_CAR, mp->mp_channel);
882: cd1400_write_ccr(cd, CD1400_CCR_CMDRESET);
883:
884: /* encode the port number in top half of LIVR */
885: CD1400_WRITE_REG(cd, CD1400_LIVR, port << 4);
886:
887: /* sets parameters and raises DTR */
888: (void)mtty_param(tp, &tp->t_termios);
889:
890: /* set tty watermarks */
891: ttsetwater(tp);
892:
893: /* enable service requests */
894: CD1400_WRITE_REG(cd, CD1400_SRER, CD1400_SRER_RXDATA | CD1400_SRER_MDMCH);
895:
896: /* tell the tty about the carrier status */
897: if (ISSET(mp->mp_openflags, TIOCFLAG_SOFTCAR) || mp->mp_carrier)
898: SET(tp->t_state, TS_CARR_ON);
899: else
900: CLR(tp->t_state, TS_CARR_ON);
901: } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) {
902: return (EBUSY); /* superuser can break exclusive access */
903: } else {
904: s = spltty();
905: }
906:
907: /* wait for carrier if necessary */
908: if (!ISSET(flags, O_NONBLOCK)) {
909: while (!ISSET(tp->t_cflag, CLOCAL) && !ISSET(tp->t_state, TS_CARR_ON)) {
910: int error;
911:
912: SET(tp->t_state, TS_WOPEN);
913: error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, "mttydcd", 0);
914: if (error != 0) {
915: splx(s);
916: CLR(tp->t_state, TS_WOPEN);
917: return (error);
918: }
919: }
920: }
921:
922: splx(s);
923:
924: return ((*linesw[tp->t_line].l_open)(dev, tp));
925: }
926:
927: /*
928: * close routine. returns zero if successful, else error code
929: */
930: int
931: mttyclose(dev_t dev, int flag, int mode, struct proc *p)
932: {
933: struct mtty_softc *ms = mtty_cd.cd_devs[MAGMA_CARD(dev)];
934: struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(dev)];
935: struct tty *tp = mp->mp_tty;
936: int s;
937:
938: (*linesw[tp->t_line].l_close)(tp, flag);
939: s = spltty();
940:
941: /* if HUPCL is set, and the tty is no longer open
942: * shut down the port
943: */
944: if (ISSET(tp->t_cflag, HUPCL) || !ISSET(tp->t_state, TS_ISOPEN)) {
945: /* XXX wait until FIFO is empty before turning off the channel
946: struct cd1400 *cd = mp->mp_cd1400;
947: */
948:
949: /* drop DTR and RTS */
950: (void)mtty_modem_control(mp, 0, DMSET);
951:
952: /* turn off the channel
953: CD1400_WRITE_REG(cd, CD1400_CAR, mp->mp_channel);
954: cd1400_write_ccr(cd, CD1400_CCR_CMDRESET);
955: */
956: }
957:
958: splx(s);
959: ttyclose(tp);
960:
961: return (0);
962: }
963:
964: /*
965: * Read routine
966: */
967: int
968: mttyread(dev_t dev, struct uio *uio, int flags)
969: {
970: struct mtty_softc *ms = mtty_cd.cd_devs[MAGMA_CARD(dev)];
971: struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(dev)];
972: struct tty *tp = mp->mp_tty;
973:
974: return ((*linesw[tp->t_line].l_read)(tp, uio, flags));
975: }
976:
977: /*
978: * Write routine
979: */
980: int
981: mttywrite(dev_t dev, struct uio *uio, int flags)
982: {
983: struct mtty_softc *ms = mtty_cd.cd_devs[MAGMA_CARD(dev)];
984: struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(dev)];
985: struct tty *tp = mp->mp_tty;
986:
987: return ((*linesw[tp->t_line].l_write)(tp, uio, flags));
988: }
989:
990: /*
991: * return tty pointer
992: */
993: struct tty *
994: mttytty(dev_t dev)
995: {
996: struct mtty_softc *ms = mtty_cd.cd_devs[MAGMA_CARD(dev)];
997: struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(dev)];
998:
999: return (mp->mp_tty);
1000: }
1001:
1002: /*
1003: * ioctl routine
1004: */
1005: int
1006: mttyioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
1007: {
1008: struct mtty_softc *ms = mtty_cd.cd_devs[MAGMA_CARD(dev)];
1009: struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(dev)];
1010: struct tty *tp = mp->mp_tty;
1011: int error;
1012:
1013: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flags, p);
1014: if (error >= 0)
1015: return (error);
1016:
1017: error = ttioctl(tp, cmd, data, flags, p);
1018: if (error >= 0)
1019: return (error);
1020:
1021: error = 0;
1022:
1023: switch(cmd) {
1024: case TIOCSBRK: /* set break */
1025: SET(mp->mp_flags, MTTYF_SET_BREAK);
1026: cd1400_enable_transmitter(mp->mp_cd1400, mp->mp_channel);
1027: break;
1028:
1029: case TIOCCBRK: /* clear break */
1030: SET(mp->mp_flags, MTTYF_CLR_BREAK);
1031: cd1400_enable_transmitter(mp->mp_cd1400, mp->mp_channel);
1032: break;
1033:
1034: case TIOCSDTR: /* set DTR */
1035: mtty_modem_control(mp, TIOCM_DTR, DMBIS);
1036: break;
1037:
1038: case TIOCCDTR: /* clear DTR */
1039: mtty_modem_control(mp, TIOCM_DTR, DMBIC);
1040: break;
1041:
1042: case TIOCMSET: /* set modem lines */
1043: mtty_modem_control(mp, *((int *)data), DMSET);
1044: break;
1045:
1046: case TIOCMBIS: /* bit set modem lines */
1047: mtty_modem_control(mp, *((int *)data), DMBIS);
1048: break;
1049:
1050: case TIOCMBIC: /* bit clear modem lines */
1051: mtty_modem_control(mp, *((int *)data), DMBIC);
1052: break;
1053:
1054: case TIOCMGET: /* get modem lines */
1055: *((int *)data) = mtty_modem_control(mp, 0, DMGET);
1056: break;
1057:
1058: case TIOCGFLAGS:
1059: *((int *)data) = mp->mp_openflags;
1060: break;
1061:
1062: case TIOCSFLAGS:
1063: if (suser(p, 0))
1064: error = EPERM;
1065: else
1066: mp->mp_openflags = *((int *)data) &
1067: (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL |
1068: TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF);
1069: break;
1070:
1071: default:
1072: error = ENOTTY;
1073: }
1074:
1075: return (error);
1076: }
1077:
1078: /*
1079: * Stop output, e.g., for ^S or output flush.
1080: */
1081: int
1082: mttystop(struct tty *tp, int flags)
1083: {
1084: struct mtty_softc *ms = mtty_cd.cd_devs[MAGMA_CARD(tp->t_dev)];
1085: struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(tp->t_dev)];
1086: int s;
1087:
1088: s = spltty();
1089:
1090: if (ISSET(tp->t_state, TS_BUSY)) {
1091: if (!ISSET(tp->t_state, TS_TTSTOP))
1092: SET(tp->t_state, TS_FLUSH);
1093:
1094: /*
1095: * the transmit interrupt routine will disable transmit when it
1096: * notices that MTTYF_STOP has been set.
1097: */
1098: SET(mp->mp_flags, MTTYF_STOP);
1099: }
1100:
1101: splx(s);
1102: return (0);
1103: }
1104:
1105: /*
1106: * Start output, after a stop.
1107: */
1108: void
1109: mtty_start(struct tty *tp)
1110: {
1111: struct mtty_softc *ms = mtty_cd.cd_devs[MAGMA_CARD(tp->t_dev)];
1112: struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(tp->t_dev)];
1113: int s;
1114:
1115: s = spltty();
1116:
1117: /* we only need to do something if we are not already busy
1118: * or delaying or stopped
1119: */
1120: if (!ISSET(tp->t_state, TS_TTSTOP | TS_TIMEOUT | TS_BUSY)) {
1121:
1122: /* if we are sleeping and output has drained below
1123: * low water mark, awaken
1124: */
1125: if (tp->t_outq.c_cc <= tp->t_lowat) {
1126: if (ISSET(tp->t_state, TS_ASLEEP)) {
1127: CLR(tp->t_state, TS_ASLEEP);
1128: wakeup(&tp->t_outq);
1129: }
1130:
1131: selwakeup(&tp->t_wsel);
1132: }
1133:
1134: /* if something to send, start transmitting
1135: */
1136: if (tp->t_outq.c_cc) {
1137: mp->mp_txc = ndqb(&tp->t_outq, 0);
1138: mp->mp_txp = tp->t_outq.c_cf;
1139: SET(tp->t_state, TS_BUSY);
1140: cd1400_enable_transmitter(mp->mp_cd1400, mp->mp_channel);
1141: }
1142: }
1143:
1144: splx(s);
1145: }
1146:
1147: /*
1148: * set/get modem line status
1149: *
1150: * bits can be: TIOCM_DTR, TIOCM_RTS, TIOCM_CTS, TIOCM_CD, TIOCM_RI, TIOCM_DSR
1151: *
1152: * note that DTR and RTS lines are exchanged, and that DSR is
1153: * not available on the LC2+1Sp card (used as CD)
1154: *
1155: * only let them fiddle with RTS if CRTSCTS is not enabled
1156: */
1157: int
1158: mtty_modem_control(struct mtty_port *mp, int bits, int howto)
1159: {
1160: struct cd1400 *cd = mp->mp_cd1400;
1161: struct tty *tp = mp->mp_tty;
1162: int s, msvr;
1163:
1164: s = spltty();
1165:
1166: CD1400_WRITE_REG(cd, CD1400_CAR, mp->mp_channel);
1167:
1168: switch(howto) {
1169: case DMGET: /* get bits */
1170: bits = 0;
1171:
1172: bits |= TIOCM_LE;
1173:
1174: msvr = CD1400_READ_REG(cd, CD1400_MSVR1);
1175: if (msvr & CD1400_MSVR1_RTS)
1176: bits |= TIOCM_DTR;
1177:
1178: msvr = CD1400_READ_REG(cd, CD1400_MSVR2);
1179: if (msvr & CD1400_MSVR2_DTR)
1180: bits |= TIOCM_RTS;
1181: if (msvr & CD1400_MSVR2_CTS)
1182: bits |= TIOCM_CTS;
1183: if (msvr & CD1400_MSVR2_RI)
1184: bits |= TIOCM_RI;
1185: if (msvr & CD1400_MSVR2_DSR)
1186: bits |= (cd->cd_parmode ? TIOCM_CD : TIOCM_DSR);
1187: if (msvr & CD1400_MSVR2_CD)
1188: bits |= (cd->cd_parmode ? 0 : TIOCM_CD);
1189:
1190: break;
1191:
1192: case DMSET: /* reset bits */
1193: if (!ISSET(tp->t_cflag, CRTSCTS))
1194: CD1400_WRITE_REG(cd, CD1400_MSVR2,
1195: ((bits & TIOCM_RTS) ? CD1400_MSVR2_DTR : 0));
1196:
1197: CD1400_WRITE_REG(cd, CD1400_MSVR1,
1198: ((bits & TIOCM_DTR) ? CD1400_MSVR1_RTS : 0));
1199:
1200: break;
1201:
1202: case DMBIS: /* set bits */
1203: if ((bits & TIOCM_RTS) && !ISSET(tp->t_cflag, CRTSCTS))
1204: CD1400_WRITE_REG(cd, CD1400_MSVR2, CD1400_MSVR2_DTR);
1205:
1206: if (bits & TIOCM_DTR)
1207: CD1400_WRITE_REG(cd, CD1400_MSVR1, CD1400_MSVR1_RTS);
1208:
1209: break;
1210:
1211: case DMBIC: /* clear bits */
1212: if ((bits & TIOCM_RTS) && !ISSET(tp->t_cflag, CRTSCTS))
1213: CD1400_WRITE_REG(cd, CD1400_MSVR2, 0);
1214:
1215: if (bits & TIOCM_DTR)
1216: CD1400_WRITE_REG(cd, CD1400_MSVR1, 0);
1217:
1218: break;
1219: }
1220:
1221: splx(s);
1222: return (bits);
1223: }
1224:
1225: /*
1226: * Set tty parameters, returns error or 0 on success
1227: */
1228: int
1229: mtty_param(struct tty *tp, struct termios *t)
1230: {
1231: struct mtty_softc *ms = mtty_cd.cd_devs[MAGMA_CARD(tp->t_dev)];
1232: struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(tp->t_dev)];
1233: struct cd1400 *cd = mp->mp_cd1400;
1234: int rbpr, tbpr, rcor, tcor;
1235: u_char mcor1 = 0, mcor2 = 0;
1236: int s, opt;
1237:
1238: if (t->c_ospeed &&
1239: cd1400_compute_baud(t->c_ospeed, cd->cd_clock, &tcor, &tbpr))
1240: return (EINVAL);
1241:
1242: if (t->c_ispeed &&
1243: cd1400_compute_baud(t->c_ispeed, cd->cd_clock, &rcor, &rbpr))
1244: return (EINVAL);
1245:
1246: s = spltty();
1247:
1248: /* hang up the line if ospeed is zero, else raise DTR */
1249: (void)mtty_modem_control(mp, TIOCM_DTR,
1250: (t->c_ospeed == 0 ? DMBIC : DMBIS));
1251:
1252: /* select channel, done in mtty_modem_control() */
1253: /* CD1400_WRITE_REG(cd, CD1400_CAR, mp->mp_channel); */
1254:
1255: /* set transmit speed */
1256: if (t->c_ospeed) {
1257: CD1400_WRITE_REG(cd, CD1400_TCOR, tcor);
1258: CD1400_WRITE_REG(cd, CD1400_TBPR, tbpr);
1259: }
1260:
1261: /* set receive speed */
1262: if (t->c_ispeed) {
1263: CD1400_WRITE_REG(cd, CD1400_RCOR, rcor);
1264: CD1400_WRITE_REG(cd, CD1400_RBPR, rbpr);
1265: }
1266:
1267: /* enable transmitting and receiving on this channel */
1268: opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN | CD1400_CCR_RCVEN;
1269: cd1400_write_ccr(cd, opt);
1270:
1271: /* set parity, data and stop bits */
1272: opt = 0;
1273: if (ISSET(t->c_cflag, PARENB))
1274: opt |= (ISSET(t->c_cflag, PARODD) ? CD1400_COR1_PARODD : CD1400_COR1_PARNORMAL);
1275:
1276: if (!ISSET(t->c_iflag, INPCK))
1277: opt |= CD1400_COR1_NOINPCK; /* no parity checking */
1278:
1279: if (ISSET(t->c_cflag, CSTOPB))
1280: opt |= CD1400_COR1_STOP2;
1281:
1282: switch( t->c_cflag & CSIZE) {
1283: case CS5:
1284: opt |= CD1400_COR1_CS5;
1285: break;
1286:
1287: case CS6:
1288: opt |= CD1400_COR1_CS6;
1289: break;
1290:
1291: case CS7:
1292: opt |= CD1400_COR1_CS7;
1293: break;
1294:
1295: default:
1296: opt |= CD1400_COR1_CS8;
1297: break;
1298: }
1299:
1300: CD1400_WRITE_REG(cd, CD1400_COR1, opt);
1301:
1302: /*
1303: * enable Embedded Transmit Commands (for breaks)
1304: * use the CD1400 automatic CTS flow control if CRTSCTS is set
1305: */
1306: opt = CD1400_COR2_ETC;
1307: if (ISSET(t->c_cflag, CRTSCTS))
1308: opt |= CD1400_COR2_CCTS_OFLOW;
1309: CD1400_WRITE_REG(cd, CD1400_COR2, opt);
1310:
1311: CD1400_WRITE_REG(cd, CD1400_COR3, MTTY_RX_FIFO_THRESHOLD);
1312:
1313: cd1400_write_ccr(cd, CD1400_CCR_CMDCORCHG | CD1400_CCR_COR1 | CD1400_CCR_COR2 | CD1400_CCR_COR3);
1314:
1315: CD1400_WRITE_REG(cd, CD1400_COR4, CD1400_COR4_PFO_EXCEPTION);
1316: CD1400_WRITE_REG(cd, CD1400_COR5, 0);
1317:
1318: /*
1319: * if automatic RTS handshaking enabled, set DTR threshold
1320: * (RTS and DTR lines are switched, CD1400 thinks its DTR)
1321: */
1322: if (ISSET(t->c_cflag, CRTSCTS))
1323: mcor1 = MTTY_RX_DTR_THRESHOLD;
1324:
1325: /* set up `carrier detect' interrupts */
1326: if (cd->cd_parmode) {
1327: SET(mcor1, CD1400_MCOR1_DSRzd);
1328: SET(mcor2, CD1400_MCOR2_DSRod);
1329: } else {
1330: SET(mcor1, CD1400_MCOR1_CDzd);
1331: SET(mcor2, CD1400_MCOR2_CDod);
1332: }
1333:
1334: CD1400_WRITE_REG(cd, CD1400_MCOR1, mcor1);
1335: CD1400_WRITE_REG(cd, CD1400_MCOR2, mcor2);
1336:
1337: /* receive timeout 2ms */
1338: CD1400_WRITE_REG(cd, CD1400_RTPR, 2);
1339:
1340: splx(s);
1341: return (0);
1342: }
1343:
1344: /************************************************************************
1345: *
1346: * MBPP Routines
1347: *
1348: * mbpp_match match one mbpp device
1349: * mbpp_attach attach mbpp devices
1350: * mbppopen open mbpp device
1351: * mbppclose close mbpp device
1352: * mbppread read from mbpp
1353: * mbppwrite write to mbpp
1354: * mbppioctl do ioctl on mbpp
1355: * mbpppoll do poll on mbpp
1356: * mbpp_rw general rw routine
1357: * mbpp_timeout rw timeout
1358: * mbpp_start rw start after delay
1359: * mbpp_send send data
1360: * mbpp_recv recv data
1361: */
1362:
1363: int
1364: mbpp_match(struct device *parent, void *vcf, void *args)
1365: {
1366: struct magma_softc *sc = (struct magma_softc *)parent;
1367:
1368: return (args == mbpp_match && sc->ms_board->mb_npar &&
1369: sc->ms_mbpp == NULL);
1370: }
1371:
1372: void
1373: mbpp_attach(struct device *parent, struct device *dev, void *args)
1374: {
1375: struct magma_softc *sc = (struct magma_softc *)parent;
1376: struct mbpp_softc *ms = (struct mbpp_softc *)dev;
1377: struct mbpp_port *mp;
1378: int port;
1379:
1380: sc->ms_mbpp = ms;
1381: dprintf((" addr 0x%x", ms));
1382:
1383: for (port = 0 ; port < sc->ms_board->mb_npar ; port++) {
1384: mp = &ms->ms_port[port];
1385:
1386: if (sc->ms_ncd1190)
1387: mp->mp_cd1190 = &sc->ms_cd1190[port];
1388: else
1389: mp->mp_cd1400 = &sc->ms_cd1400[0];
1390:
1391: timeout_set(&mp->mp_timeout_tmo, mbpp_timeout, mp);
1392: timeout_set(&mp->mp_start_tmo, mbpp_start, mp);
1393: }
1394:
1395: ms->ms_nports = port;
1396: printf(": %d port%s\n", port, port == 1 ? "" : "s");
1397: }
1398:
1399: /*
1400: * open routine. returns zero if successful, else error code
1401: */
1402: int
1403: mbppopen(dev_t dev, int flags, int mode, struct proc *p)
1404: {
1405: int card = MAGMA_CARD(dev);
1406: int port = MAGMA_PORT(dev);
1407: struct mbpp_softc *ms;
1408: struct mbpp_port *mp;
1409: int s;
1410:
1411: if (card >= mbpp_cd.cd_ndevs || (ms = mbpp_cd.cd_devs[card]) == NULL || port >= ms->ms_nports)
1412: return (ENXIO);
1413:
1414: mp = &ms->ms_port[port];
1415:
1416: s = spltty();
1417: if (ISSET(mp->mp_flags, MBPPF_OPEN)) {
1418: splx(s);
1419: return (EBUSY);
1420: }
1421: SET(mp->mp_flags, MBPPF_OPEN);
1422: splx(s);
1423:
1424: /* set defaults */
1425: mp->mp_burst = BPP_BURST;
1426: mp->mp_timeout = mbpp_mstohz(BPP_TIMEOUT);
1427: mp->mp_delay = mbpp_mstohz(BPP_DELAY);
1428:
1429: /* init chips */
1430: if (mp->mp_cd1400) { /* CD1400 */
1431: struct cd1400 *cd = mp->mp_cd1400;
1432:
1433: /* set up CD1400 channel */
1434: s = spltty();
1435: CD1400_WRITE_REG(cd, CD1400_CAR, 0);
1436: cd1400_write_ccr(cd, CD1400_CCR_CMDRESET);
1437: CD1400_WRITE_REG(cd, CD1400_LIVR, (1<<3));
1438: splx(s);
1439: } else { /* CD1190 */
1440: mp->mp_flags = 0;
1441: return (ENXIO);
1442: }
1443:
1444: return (0);
1445: }
1446:
1447: /*
1448: * close routine. returns zero if successful, else error code
1449: */
1450: int
1451: mbppclose(dev_t dev, int flag, int mode, struct proc *p)
1452: {
1453: struct mbpp_softc *ms = mbpp_cd.cd_devs[MAGMA_CARD(dev)];
1454: struct mbpp_port *mp = &ms->ms_port[MAGMA_PORT(dev)];
1455:
1456: mp->mp_flags = 0;
1457: return (0);
1458: }
1459:
1460: /*
1461: * Read routine
1462: */
1463: int
1464: mbppread(dev_t dev, struct uio *uio, int flags)
1465: {
1466: return (mbpp_rw(dev, uio));
1467: }
1468:
1469: /*
1470: * Write routine
1471: */
1472: int
1473: mbppwrite(dev_t dev, struct uio *uio, int flags)
1474: {
1475: return (mbpp_rw(dev, uio));
1476: }
1477:
1478: /*
1479: * ioctl routine
1480: */
1481: int
1482: mbppioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
1483: {
1484: struct mbpp_softc *ms = mbpp_cd.cd_devs[MAGMA_CARD(dev)];
1485: struct mbpp_port *mp = &ms->ms_port[MAGMA_PORT(dev)];
1486: struct bpp_param *bp;
1487: int error = 0;
1488: int s;
1489:
1490: switch(cmd) {
1491: case BPPIOCSPARAM:
1492: bp = (struct bpp_param *)data;
1493: if (bp->bp_burst < BPP_BURST_MIN || bp->bp_burst > BPP_BURST_MAX ||
1494: bp->bp_delay < BPP_DELAY_MIN || bp->bp_delay > BPP_DELAY_MIN) {
1495: error = EINVAL;
1496: } else {
1497: mp->mp_burst = bp->bp_burst;
1498: mp->mp_timeout = mbpp_mstohz(bp->bp_timeout);
1499: mp->mp_delay = mbpp_mstohz(bp->bp_delay);
1500: }
1501: break;
1502: case BPPIOCGPARAM:
1503: bp = (struct bpp_param *)data;
1504: bp->bp_burst = mp->mp_burst;
1505: bp->bp_timeout = mbpp_hztoms(mp->mp_timeout);
1506: bp->bp_delay = mbpp_hztoms(mp->mp_delay);
1507: break;
1508: case BPPIOCGSTAT:
1509: /* XXX make this more generic */
1510: s = spltty();
1511: CD1400_WRITE_REG(mp->mp_cd1400, CD1400_CAR, 0);
1512: *(int *)data = CD1400_READ_REG(mp->mp_cd1400, CD1400_PSVR);
1513: splx(s);
1514: break;
1515: default:
1516: error = ENOTTY;
1517: }
1518:
1519: return (error);
1520: }
1521:
1522: /*
1523: * poll routine
1524: */
1525: int
1526: mbpppoll(dev_t dev, int events, struct proc *p)
1527: {
1528: return (seltrue(dev, events, p));
1529: }
1530:
1531: int
1532: mbpp_rw(dev_t dev, struct uio *uio)
1533: {
1534: int card = MAGMA_CARD(dev);
1535: int port = MAGMA_PORT(dev);
1536: struct mbpp_softc *ms = mbpp_cd.cd_devs[card];
1537: struct mbpp_port *mp = &ms->ms_port[port];
1538: caddr_t buffer, ptr;
1539: int buflen, cnt, len;
1540: int s, error = 0;
1541: int gotdata = 0;
1542:
1543: if (uio->uio_resid == 0)
1544: return (0);
1545:
1546: buflen = min(uio->uio_resid, mp->mp_burst);
1547: buffer = malloc(buflen, M_DEVBUF, M_WAITOK);
1548:
1549: SET(mp->mp_flags, MBPPF_UIO);
1550:
1551: /*
1552: * start timeout, if needed
1553: */
1554: if (mp->mp_timeout > 0) {
1555: SET(mp->mp_flags, MBPPF_TIMEOUT);
1556: timeout_add(&mp->mp_timeout_tmo, mp->mp_timeout);
1557: }
1558:
1559: len = cnt = 0;
1560: while (uio->uio_resid > 0) {
1561: len = min(buflen, uio->uio_resid);
1562: ptr = buffer;
1563:
1564: if (uio->uio_rw == UIO_WRITE) {
1565: error = uiomove(ptr, len, uio);
1566: if (error)
1567: break;
1568: }
1569: again: /* goto bad */
1570: /* timed out? */
1571: if (!ISSET(mp->mp_flags, MBPPF_UIO))
1572: break;
1573:
1574: /*
1575: * perform the operation
1576: */
1577: if (uio->uio_rw == UIO_WRITE) {
1578: cnt = mbpp_send(mp, ptr, len);
1579: } else {
1580: cnt = mbpp_recv(mp, ptr, len);
1581: }
1582:
1583: if (uio->uio_rw == UIO_READ) {
1584: if (cnt) {
1585: error = uiomove(ptr, cnt, uio);
1586: if (error)
1587: break;
1588: gotdata++;
1589: }
1590: else if (gotdata) /* consider us done */
1591: break;
1592: }
1593:
1594: /* timed out? */
1595: if (!ISSET(mp->mp_flags, MBPPF_UIO))
1596: break;
1597:
1598: /*
1599: * poll delay?
1600: */
1601: if (mp->mp_delay > 0) {
1602: s = spltty(); /* XXX */
1603: SET(mp->mp_flags, MBPPF_DELAY);
1604: timeout_add(&mp->mp_start_tmo, mp->mp_delay);
1605: error = tsleep(mp, PCATCH | PZERO, "mbppdelay", 0);
1606: splx(s);
1607: if (error)
1608: break;
1609: }
1610:
1611: /*
1612: * don't call uiomove again until we used all the data we grabbed
1613: */
1614: if (uio->uio_rw == UIO_WRITE && cnt != len) {
1615: ptr += cnt;
1616: len -= cnt;
1617: cnt = 0;
1618: goto again;
1619: }
1620: }
1621:
1622: /*
1623: * clear timeouts
1624: */
1625: s = spltty(); /* XXX */
1626: if (ISSET(mp->mp_flags, MBPPF_TIMEOUT)) {
1627: timeout_del(&mp->mp_timeout_tmo);
1628: CLR(mp->mp_flags, MBPPF_TIMEOUT);
1629: }
1630: if (ISSET(mp->mp_flags, MBPPF_DELAY)) {
1631: timeout_del(&mp->mp_start_tmo);
1632: CLR(mp->mp_flags, MBPPF_DELAY);
1633: }
1634: splx(s);
1635:
1636: /*
1637: * adjust for those chars that we uiomoved but never actually wrote
1638: */
1639: if (uio->uio_rw == UIO_WRITE && cnt != len) {
1640: uio->uio_resid += (len - cnt);
1641: }
1642:
1643: free(buffer, M_DEVBUF);
1644: return (error);
1645: }
1646:
1647: void
1648: mbpp_timeout(void *arg)
1649: {
1650: struct mbpp_port *mp = arg;
1651:
1652: CLR(mp->mp_flags, MBPPF_UIO | MBPPF_TIMEOUT);
1653: wakeup(mp);
1654: }
1655:
1656: void
1657: mbpp_start(void *arg)
1658: {
1659: struct mbpp_port *mp = arg;
1660:
1661: CLR(mp->mp_flags, MBPPF_DELAY);
1662: wakeup(mp);
1663: }
1664:
1665: int
1666: mbpp_send(struct mbpp_port *mp, caddr_t ptr, int len)
1667: {
1668: int s;
1669: struct cd1400 *cd = mp->mp_cd1400;
1670:
1671: /* set up io information */
1672: mp->mp_ptr = ptr;
1673: mp->mp_cnt = len;
1674:
1675: /* start transmitting */
1676: s = spltty();
1677: if (cd) {
1678: CD1400_WRITE_REG(cd, CD1400_CAR, 0);
1679:
1680: /* output strobe width ~1microsecond */
1681: CD1400_WRITE_REG(cd, CD1400_TBPR, 10);
1682:
1683: /* enable channel */
1684: cd1400_write_ccr(cd, CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN);
1685: CD1400_WRITE_REG(cd, CD1400_SRER, CD1400_SRER_TXRDY);
1686: }
1687:
1688: /* ZZzzz... */
1689: tsleep(mp, PCATCH | PZERO, "mbpp_send", 0);
1690:
1691: /* stop transmitting */
1692: if (cd) {
1693: CD1400_WRITE_REG(cd, CD1400_CAR, 0);
1694:
1695: /* disable transmitter */
1696: CD1400_WRITE_REG(cd, CD1400_SRER, 0);
1697: cd1400_write_ccr(cd, CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTDIS);
1698:
1699: /* flush fifo */
1700: cd1400_write_ccr(cd, CD1400_CCR_CMDRESET | CD1400_CCR_FTF);
1701: }
1702: splx(s);
1703:
1704: /* return number of chars sent */
1705: return (len - mp->mp_cnt);
1706: }
1707:
1708: int
1709: mbpp_recv(struct mbpp_port *mp, caddr_t ptr, int len)
1710: {
1711: int s;
1712: struct cd1400 *cd = mp->mp_cd1400;
1713:
1714: /* set up io information */
1715: mp->mp_ptr = ptr;
1716: mp->mp_cnt = len;
1717:
1718: /* start receiving */
1719: s = spltty();
1720: if (cd) {
1721: int rcor, rbpr;
1722:
1723: CD1400_WRITE_REG(cd, CD1400_CAR, 0);
1724:
1725: /* input strobe at 100kbaud (10microseconds) */
1726: cd1400_compute_baud(100000, cd->cd_clock, &rcor, &rbpr);
1727: CD1400_WRITE_REG(cd, CD1400_RCOR, rcor);
1728: CD1400_WRITE_REG(cd, CD1400_RBPR, rbpr);
1729:
1730: /* rx threshold */
1731: CD1400_WRITE_REG(cd, CD1400_COR3, MBPP_RX_FIFO_THRESHOLD);
1732: cd1400_write_ccr(cd, CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3);
1733:
1734: /* enable channel */
1735: cd1400_write_ccr(cd, CD1400_CCR_CMDCHANCTL | CD1400_CCR_RCVEN);
1736: CD1400_WRITE_REG(cd, CD1400_SRER, CD1400_SRER_RXDATA);
1737: }
1738:
1739: /* ZZzzz... */
1740: tsleep(mp, PCATCH | PZERO, "mbpp_recv", 0);
1741:
1742: /* stop receiving */
1743: if (cd) {
1744: CD1400_WRITE_REG(cd, CD1400_CAR, 0);
1745:
1746: /* disable receiving */
1747: CD1400_WRITE_REG(cd, CD1400_SRER, 0);
1748: cd1400_write_ccr(cd, CD1400_CCR_CMDCHANCTL | CD1400_CCR_RCVDIS);
1749: }
1750: splx(s);
1751:
1752: /* return number of chars received */
1753: return (len - mp->mp_cnt);
1754: }
1755:
1756: int
1757: mbpp_hztoms(int h)
1758: {
1759: int m = h;
1760:
1761: if (m > 0)
1762: m = m * 1000 / hz;
1763: return (m);
1764: }
1765:
1766: int
1767: mbpp_mstohz(int m)
1768: {
1769: int h = m;
1770:
1771: if (h > 0) {
1772: h = h * hz / 1000;
1773: if (h == 0)
1774: h = 1000 / hz;
1775: }
1776: return (h);
1777: }
CVSweb