FreeBSD/Linux Kernel Cross Reference
sys/i386at/if_par.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1991,1990,1989 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: if_par.c,v $
29 * Revision 2.6 93/01/24 13:17:30 danner
30 * Typo.
31 * [92/10/01 rvb]
32 *
33 * Revision 2.5 93/01/14 17:30:49 danner
34 * Proper spl typing.
35 * [92/11/30 af]
36 *
37 * Revision 2.4 92/03/01 00:40:07 rpd
38 * Cleaned up syntactically incorrect ifdefs.
39 * [92/02/29 rpd]
40 *
41 * Revision 2.3 92/02/25 15:35:52 elf
42 * Do NET_DSTADDR correctly.
43 * [92/02/21 rvb]
44 * On output side, skip ether header -- they are not put on the wire.
45 * And some cleanup
46 * [92/02/19 rvb]
47 * Add lpr and par devices. (taken from 2.5)
48 * BEING DEBUGGED -- not operational
49 * [92/02/13 rvb]
50 *
51 * Revision 2.3 91/07/15 13:42:18 mrt
52 * Don't set UNUSED bits in intr_enable.
53 * [91/06/27 mg32]
54 *
55 * Revision 2.2 91/04/02 12:08:46 mbj
56 * Changed protocol to utilitize LapLink cables. Incompatible with
57 * previous revisions.
58 * [91/03/15 mg32]
59 * Added more documentation on how we use parallel interface.
60 * [90/09/17 mg32]
61 * Created 08/05/90.
62 * Parallel port network driver.
63 * [90/08/14 mg32]
64 *
65 */
66
67 /*
68 * Parallel port network driver v1.1
69 * All rights reserved.
70 */
71
72 /*
73 Subject: parallel network interface
74
75 The printer network driver has the following hardware requirements for the
76 interconnection cable:
77
78 Connections:
79 Side1 Side2 Function Side1 / Side2
80 Pin 5 Pin 10 Interrupt strobe: send status (w)/send status (r)
81 Pin 2 Pin 15 Data bits : write / read
82 Pin 3 Pin 13 Data bits : write / read
83 Pin 4 Pin 12 Data bits : write / read
84 Pin 6 Pin 11 Data bits : write / read
85 Pin 10 Pin 5
86 Pin 11 Pin 6
87 Pin 12 Pin 4
88 Pin 13 Pin 3
89 Pin 15 Pin 2
90 Pins 18-25 Pins 18-25 (ground interconnections)
91
92 The cable is "symmetric" in that either side can be plugged into either of the
93 computers.
94
95 The hardware requirements are as follows:
96 Port 0x378 must be writable with the following specifications:
97 Bit 4 -> pin 6
98 Bit 3 -> pin 5
99 Bit 2 -> pin 4
100 Bit 1 -> pin 3
101 Bit 0 -> pin 2
102 Port 0x379 must be readable with the following specifications:
103 Bit 7 <- pin 11
104 Bit 6 <- pin 10
105 Bit 5 <- pin 12
106 Bit 4 <- pin 13
107 Bit 3 <- pin 15
108 Port 0x37a must be readable and writable with the following specifications:
109 Bit 4 -> interrupt enable
110 So Port 0x378 connects to Port 0x379 as
111 Bit 3 -> pin 5 : pin 10 -> Bit 6 0x08 -> 0x40
112
113 Bit 4 -> pin 6 : pin 11 -> Bit 7 0x08<<1 -> ~ 0x80
114 Bit 2 -> pin 4 : pin 12 -> Bit 5 0x07 -> 0x38
115 Bit 1 -> pin 3 : pin 13 -> Bit 4 0x07 -> 0x38
116 Bit 0 -> pin 2 : pin 15 -> Bit 3 0x07 -> 0x38
117 [note: bit 0 is considered the least significant bit, pins on the connector
118 are numbered starting with 1, -> represents sending data out on the bus, <-
119 represents reading data from the bus]
120
121 Pins 1,7,8,9, and 16 are currently unused, and may be allowed to "float".
122
123 The data is sent in 4 bit "nybbles", with the highest 4 bits being sent first.
124
125 To bring up the interface, all that should be required is
126 ifconfig par0 <your ip address> <connected machine's ip address> up
127 and to bring down the interface
128 ifconfig par0 down
129 You may get a warning message (such as printer out of paper) once you down
130 the interface, as the port is monitored for both printer and network activity
131 depending on whether par0 is up or down, and when you down the interface the
132 printer driver will then read whatever is on the port (which will be the last
133 message from the other computer).
134 */
135
136 #include <par.h>
137 #if NPAR > 0
138
139 #include <kern/time_out.h>
140 #include <device/device_types.h>
141 #include <device/errno.h>
142 #include <device/io_req.h>
143 #include <device/if_hdr.h>
144 #include <device/if_ether.h>
145 #include <device/net_status.h>
146 #include <device/net_io.h>
147
148 #include <i386/ipl.h>
149 #include <i386/pio.h>
150 #include <chips/busses.h>
151 #include <i386at/if_par.h>
152
153
154 int parintr();
155 int parioctl();
156 int parattach();
157 int paroutput();
158
159 int (*oldvect)();
160 int oldunit;
161
162 extern struct bus_device *lprinfo[];
163
164 int par_watch = 0;
165
166 struct par_softc {
167 struct ifnet ds_if;
168 u_char ds_addr[6]; /* Ethernet hardware address */
169 u_char address[6];
170 char sc_buf[PARMTU+sizeof(struct ifnet *)];
171 } par_softc[NPAR];
172
173 void parintoff(unit)
174 int unit;
175 {
176 struct bus_device *lpdev = lprinfo[unit];
177
178 outb(INTR(lpdev->address), 0x07);
179 par_softc[unit].ds_if.if_flags &= ~IFF_RUNNING;
180 ivect[lpdev->sysdep1] = oldvect;
181 iunit[lpdev->sysdep1] = oldunit;
182 }
183
184 void parinit(unit)
185 int unit;
186 {
187 struct bus_device *lpdev = lprinfo[unit];
188
189 if (ivect[lpdev->sysdep1] != parintr) {
190 oldvect = ivect[lpdev->sysdep1];
191 oldunit = iunit[lpdev->sysdep1];
192 ivect[lpdev->sysdep1] = parintr;
193 iunit[lpdev->sysdep1] = unit;
194 }
195 outb(INTR(lpdev->address),0x11);
196 par_softc[unit].ds_if.if_flags |= IFF_RUNNING;
197 *(struct ifnet **)par_softc[unit].sc_buf = &par_softc[unit].ds_if;
198 }
199
200 struct ether_header par_eh;
201
202 int parattach(dev)
203 struct bus_device *dev;
204 {
205 u_char unit = (u_char)dev->unit;
206 struct ifnet *ifp;
207 struct par_softc*sp;
208
209 if ((unit < 0) || (unit >= NPAR))
210 return(0);
211 printf("\n par%d: at lpr%d, port = %x, spl = %d, pic = %d. ",
212 unit, unit, dev->address, dev->sysdep, dev->sysdep1);
213
214 sp = &par_softc[unit];
215 ifp = &(sp->ds_if);
216
217 *(sp->ds_addr) = *(sp->address) = 0x11;
218 *(sp->ds_addr + 1) = *(sp->address + 1) = 0x22;
219 *(sp->ds_addr + 2) = *(sp->address + 2) = 0x33;
220 *(sp->ds_addr + 3) = *(sp->address + 3) = 0x44;
221 *(sp->ds_addr + 4) = *(sp->address + 4) = 0x55;
222 *(sp->ds_addr + 5) = *(sp->address + 5) = 0x66;
223
224 par_eh.ether_dhost[5] = par_eh.ether_shost[0] = 0x11;
225 par_eh.ether_dhost[4] = par_eh.ether_shost[1] = 0x22;
226 par_eh.ether_dhost[3] = par_eh.ether_shost[2] = 0x33;
227 par_eh.ether_dhost[2] = par_eh.ether_shost[3] = 0x44;
228 par_eh.ether_dhost[1] = par_eh.ether_shost[4] = 0x55;
229 par_eh.ether_dhost[0] = par_eh.ether_shost[5] = 0x66;
230 par_eh.ether_type = htons(0x0800);
231
232 printf("ethernet id [%x:%x:%x:%x:%x:%x]",
233 sp->address[0],sp->address[1],sp->address[2],
234 sp->address[3],sp->address[4],sp->address[5]);
235
236 ifp->if_unit = unit;
237 ifp->if_mtu = ETHERMTU;
238 ifp->if_flags = IFF_POINTOPOINT;
239 ifp->if_header_size = sizeof(struct ether_header);
240 ifp->if_header_format = HDR_ETHERNET;
241 ifp->if_address_size = 6;
242 ifp->if_address = (char *)&par_softc[unit].address[0];
243 if_init_queues(ifp);
244 return(0);
245 }
246
247 int parstart(); /* forward */
248
249 /*ARGSUSED*/
250 paropen(dev, flag)
251 dev_t dev;
252 int flag;
253 {
254 register int unit = minor(dev);
255
256 if (unit < 0 || unit >= NPAR)
257 return (ENXIO);
258
259 par_softc[unit].ds_if.if_flags |= IFF_UP;
260 parinit(unit);
261 return(0);
262 }
263
264 paroutput(dev, ior)
265 dev_t dev;
266 io_req_t ior;
267 {
268 register int unit = minor(dev);
269
270 if (unit < 0 || unit >= NPAR)
271 return (ENXIO);
272 return (net_write(&par_softc[unit].ds_if, parstart, ior));
273 }
274
275 parsetinput(dev, receive_port, priority, filter, filter_count)
276 dev_t dev;
277 mach_port_t receive_port;
278 int priority;
279 filter_t filter[];
280 unsigned int filter_count;
281 {
282 register int unit = minor(dev);
283
284 if (unit < 0 || unit >= NPAR)
285 return (ENXIO);
286
287 return (net_set_filter(&par_softc[unit].ds_if,
288 receive_port, priority,
289 filter, filter_count));
290 }
291
292 int parstart(unit)
293 {
294 struct ifnet *ifp = &(par_softc[unit].ds_if);
295 u_short addr = lprinfo[unit]->address;
296 struct sockaddr *dst;
297 int len, i;
298 spl_t s;
299 u_char *mcp, c;
300 io_req_t m;
301
302 if (!(ifp->if_flags & IFF_RUNNING)) {
303 #ifdef WHY
304 m_free(m);
305 parintoff(unit);
306 return(ENETDOWN);
307 #else WHY
308 parintoff(unit);
309 return(-1);
310 #endif WHY
311 }
312 s = SPLNET();
313
314 IF_DEQUEUE(&ifp->if_snd, m);
315 if (m == 0) {
316 splx(s);
317 return 0;
318 }
319 len = m->io_count;
320 if (par_watch)
321 printf("O%d\n",len);
322 len -= 14 /* XXX */;
323 mcp = (u_char *)m->io_data + 14 /* XXX */;
324 while (len--) {
325 c=*mcp++;
326 outb(OUTPUT(addr),((c&0x80)>>3) | ((c&0x70)>>4) | 0x08);
327 i=MAXSPIN;
328 while (!(inb(INPUT(addr))&0x40) && --i);
329 outb(OUTPUT(addr),((c&0x08)<<1) | (c&0x07));
330 i=MAXSPIN;
331 while ((inb(INPUT(addr))&0x40) && --i);
332 }
333 outb(OUTPUT(addr),(((c&0x08)<<1) | (c&0x07))^0x17);
334 iodone(m);
335 splx(s);
336 return (0);
337 }
338
339 /*ARGSUSED*/
340 pargetstat(dev, flavor, status, count)
341 dev_t dev;
342 int flavor;
343 dev_status_t status; /* pointer to OUT array */
344 unsigned int *count; /* out */
345 {
346 register int unit = minor(dev);
347
348 if (unit < 0 || unit >= NPAR)
349 return (ENXIO);
350
351
352 switch (flavor) {
353 case NET_DSTADDR:
354 return (D_SUCCESS);
355 break;
356 }
357
358 return (net_getstat(&par_softc[unit].ds_if,
359 flavor,
360 status,
361 count));
362 }
363
364 parsetstat(dev, flavor, status, count)
365 dev_t dev;
366 int flavor;
367 dev_status_t status;
368 unsigned int count;
369 {
370 register int unit = minor(dev);
371 register struct par_softc *sp;
372
373 if (unit < 0 || unit >= NPAR)
374 return (ENXIO);
375
376 sp = &par_softc[unit];
377
378 switch (flavor) {
379 case NET_STATUS:
380 {
381 /*
382 * All we can change are flags, and not many of those.
383 */
384 register struct net_status *ns = (struct net_status *)status;
385 int mode = 0;
386
387 if (count < NET_STATUS_COUNT)
388 return (D_INVALID_SIZE);
389
390 #if 0
391 /* ha ha ha */
392 if (ns->flags & IFF_ALLMULTI)
393 mode |= MOD_ENAL;
394 if (ns->flags & IFF_PROMISC)
395 mode |= MOD_PROM;
396 /*
397 * Force a complete reset if the receive mode changes
398 * so that these take effect immediately.
399 */
400 if (sp->mode != mode) {
401 sp->mode = mode;
402 if (sp->flags & DSF_RUNNING) {
403 sp->flags &= ~(DSF_LOCK | DSF_RUNNING);
404 parinit(unit);
405 }
406 }
407 #endif
408 break;
409 }
410 case NET_ADDRESS:
411 {
412 register union ether_cvt {
413 char addr[6];
414 int lwd[2];
415 } *ec = (union ether_cvt *)status;
416
417 if (count < sizeof(*ec)/sizeof(int))
418 return (D_INVALID_SIZE);
419
420 ec->lwd[0] = ntohl(ec->lwd[0]);
421 ec->lwd[1] = ntohl(ec->lwd[1]);
422 /* at3c501seteh(sp->base, ec->addr);*/
423 break;
424 }
425
426 default:
427 return (D_INVALID_OPERATION);
428 }
429 return (D_SUCCESS);
430 }
431
432 int parintr(unit)
433 int unit;
434 {
435 register struct par_softc *sp = &par_softc[unit];
436 u_short addr = lprinfo[unit]->address;
437 char *trav = sp->sc_buf;
438 short len = 0;
439 u_char c, c2;
440 int i;
441 ipc_kmsg_t new_kmsg;
442 struct ether_header *ehp;
443 struct packet_header *pkt;
444 struct ifnet *ifp = &(sp->ds_if);
445
446 do {
447 c2=inb(INPUT(addr));
448 outb(OUTPUT(addr),0x08);
449 i=MAXSPIN;
450 while(((c=inb(INPUT(addr)))&0x40) && --i);
451
452 c = inb(INPUT(addr));
453 outb(OUTPUT(addr),0x00);
454 if (!i)
455 break;
456
457 if (++len > ETHERMTU) {
458 trav = sp->sc_buf;
459 len = 0;
460 continue;
461 }
462 *trav++ = ((~c2)&0x80) | ((c2&0x38)<<1) | (((~c)&0x80)>>4) | ((c&0x38)>>3);
463 i=MAXSPIN;
464 while (!((c2=inb(INPUT(addr)))&0x40) && --i)
465 if (((c2^0xb8)&0xf8) == (c&0xf8))
466 goto end;
467 } while (i);
468 end:
469 if (len < 20) /* line noise ? */
470 return;
471 if (par_watch)
472 printf("I%d\n",len);
473
474 new_kmsg = net_kmsg_get();
475 if (new_kmsg == IKM_NULL) {
476 /*
477 * Drop the packet.
478 */
479 sp->ds_if.if_rcvdrops++;
480 return;
481 }
482 ehp = (struct ether_header *) (&net_kmsg(new_kmsg)->header[0]);
483 pkt = (struct packet_header *) (&net_kmsg(new_kmsg)->packet[0]);
484 *ehp = par_eh;
485
486 bcopy (sp->sc_buf, (char *) (pkt + 1), len);
487
488 pkt->type = ehp->ether_type;
489 pkt->length = len + sizeof(struct packet_header);
490 /*
491 * Hand the packet to the network module.
492 */
493 net_packet(ifp, new_kmsg, pkt->length,
494 ethernet_priority(new_kmsg));
495 return(0);
496 }
497 #endif
Cache object: a3c12a14774edbd170a0e24436f0a758
|