summaryrefslogtreecommitdiff
path: root/2003/i/buzz/src/kernel/pbus.c
blob: 7d28fff916c3ec9a1837d142b0496f74df6820ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/conf.h>
#include <sys/ioctl.h>

#include <ioconf.h>
#include <machine/bonito_io.h>
#include <arch/bonito/dev/tests/pbus.h>


/* autoconfig stuff... */

#define	BUFSZ		(256<<10)
#define DMASIZE		(2*BUFSZ)

struct pbus_softc {
	struct device sc_dev;	/* REQUIRED first entry */
  	void *sc_ih;			/* interrupt handle */
	bus_space_tag_t iot;
	bus_space_handle_t ioh;
	bus_dma_tag_t dmat;
	unsigned long iobase;
  	bus_dmamap_t	sc_dmam;	/* bus dma map */
  	unsigned char  *sc_cpudma;	/* dma memory space from cpu space*/
  	unsigned long	sc_bonitodma;	/* dma memory space from pci space*/
  	unsigned long	sc_dmasize;	/* dma buffer size */
	struct proc *cproc;		/* Control process */
	int csignal;			/* Control signal */
	int in_dma;
	int buf_ok;
	int framesize;
	int buf_consumed;
	int pbusinten;
};

static int	pbusprobe(struct device *, struct cfdata *, void *);
static void	pbusattach(struct device *, struct device *, void *);

struct cfattach pbus_ca = {
	sizeof(struct pbus_softc), pbusprobe, pbusattach
};

#define BUFSYNC_PRE \
  bus_dmamap_sync(sc->dmat,sc->sc_dmam,0,DMASIZE,BUS_DMASYNC_PREREAD)
#define BUFSYNC_POST \
  bus_dmamap_sync(sc->dmat,sc->sc_dmam,0,DMASIZE,BUS_DMASYNC_POSTREAD)

#define PBUS_WRITE_4(reg, val) \
	bus_space_write_4(sc->iot, sc->ioh, reg, val)
#define PBUS_READ_4(reg)  \
	bus_space_read_4(sc->iot, sc->ioh, reg)

static int	
pbusprobe(struct device *parent, struct cfdata *cf, void *aux)
{
 struct bonito_io_attach *bia = aux;
 struct pbus_softc scp;
 struct pbus_softc *sc=&scp;
 sc->iobase=bia->base;
 
 return 1;
}

int pbus_intr(void *p);

static void
pbusattach(parent, self, aux)
	struct device	*parent, *self;
	void		*aux;
{
  	bus_dma_segment_t seg;
  	int rseg;
	struct bonito_io_attach *bia = aux;
	struct pbus_softc *sc = (struct pbus_softc *)self;
	
	sc->iot=bia->iot;
	sc->dmat=bia->dmat;
	bus_space_map(sc->iot, bia->base, 12, 0, &(sc->ioh));

	sc->iobase=(unsigned long)sc->ioh;
	printf("\n");


  PBUS_WRITE_4(0x08,PBUS_RnW);
  PBUS_WRITE_4(0x0,0);
  sc->sc_dmasize=DMASIZE;
  sc->in_dma=0;
  sc->buf_ok=0;
  sc->framesize=BUFSZ;
  sc->csignal=SIGUSR1;
  sc->pbusinten=0;
  sc->buf_consumed=0;
 
  /*
   * Allocate a DMA area for the card.
   */
  if (bus_dmamem_alloc(sc->dmat, sc->sc_dmasize, NBPG, 0, &seg, 1,
		       &rseg, BUS_DMA_NOWAIT|BUS_DMA_DIRECT))
  {
    printf("%s: couldn't allocate DMA\n",
	   sc->sc_dev.dv_xname);
    return;
  }
  if (bus_dmamem_map(sc->dmat, &seg, rseg, sc->sc_dmasize,
		     (caddr_t *)&sc->sc_cpudma,
		     BUS_DMA_NOWAIT|BUS_DMA_DIRECT))
  {
    printf("%s: couldn't map DMA\n",
	   sc->sc_dev.dv_xname);
    return;
  }

  /*
   * Create and load the DMA map for the DMA area.
   */
  if (bus_dmamap_create(sc->dmat, sc->sc_dmasize, 1,
			sc->sc_dmasize, 0, BUS_DMA_NOWAIT|BUS_DMA_DIRECT, &sc->sc_dmam))
  {
    printf("%s: couldn't create DMA map\n",
	   sc->sc_dev.dv_xname);
    bus_dmamem_free(sc->dmat, &seg, rseg);
    return;
  }
  if (bus_dmamap_load(sc->dmat, sc->sc_dmam,
		      sc->sc_cpudma, sc->sc_dmasize, NULL, BUS_DMA_NOWAIT|BUS_DMA_DIRECT))
  {
    printf("%s: coundn't load DMA map\n",
	   sc->sc_dev.dv_xname);
    bus_dmamem_free(sc->dmat, &seg, rseg);
    return;
  }

  sc->sc_bonitodma = sc->sc_dmam->dm_segs[0].ds_addr;
  bzero(sc->sc_cpudma,DMASIZE);

  sc->sc_ih = bonito_intr_establish(bia->irq, IPL_NET, pbus_intr, sc);
  if (sc->sc_ih == NULL)
  {
    printf("%s: couldn't establish interrupt at %d\n",
	   sc->sc_dev.dv_xname,bia->irq);
    return;
  }

  printf("%s: DMA map:0x%08lx (PHYS:0x%08lx)\n", sc->sc_dev.dv_xname, (unsigned long) sc->sc_cpudma, sc->sc_bonitodma);
  printf("%s: interrupting at %d\n", sc->sc_dev.dv_xname, bia->irq);

}



/*
 * operational routines:
 * open, close, read, write,
 * ioctl, mmap
 */

dev_type_open(pbusopen);
dev_type_close(pbusclose);
dev_type_read(pbusread);
dev_type_write(pbuswrite);
dev_type_ioctl(pbusioctl);
dev_type_mmap(pbusmmap);

int
pbusopen(dev, flag, fmt, proc)
	dev_t dev;
	int flag, fmt;
	struct proc *proc;
{
 struct pbus_softc *sc= pbus_cd.cd_devs[0];

	if (minor(dev)==1)	/* PBUS */
 	  sc->cproc=proc;
	return 0;
}

int
pbusclose(dev, flag, fmt, proc)
	dev_t dev;
	int flag, fmt;
	struct proc *proc;
{
 struct pbus_softc *sc= pbus_cd.cd_devs[0];
	if (minor(dev)==1)	/* PBUS */
  	  sc->cproc=NULL;
	return 0;
}

int
pbusread(dev, uio, flags)
	dev_t dev;
	struct uio *uio;
	int flags;
{
 int bufok,remain;
 int resid=uio->uio_resid;
 int s;
 struct pbus_softc *sc= pbus_cd.cd_devs[0];
 s=splhigh();
 bufok=*((volatile int *)(&sc->buf_ok));
 if ((!bufok)&&(!sc->in_dma))
 {
  BUFSYNC_PRE;
  PBUS_WRITE_4(0x4,sc->sc_bonitodma); 
  sc->in_dma=1;
 }
 splx(s);
 if (!bufok) return 0;
 remain=sc->framesize-sc->buf_consumed;
 if (resid>remain) resid=remain;
 
 uiomove(sc->sc_cpudma+sc->buf_consumed,resid,uio);
 sc->buf_consumed+=resid;
 remain-=resid;
 if (!remain)
 {
  sc->buf_consumed=0;
  sc->buf_ok=0;
 }  
 return 0;
}

int
pbuswrite(dev, uio, flags)
	dev_t dev;
	struct uio *uio;
	int flags;
{
 return ENODEV;
}

int pbus_intr(void *p)
{
 struct pbus_softc *sc = (struct pbus_softc *)p;
 unsigned long status=PBUS_READ_4(0);
 if (status&0x20000000)
 {
  /* D�sactive les interuptions. */
  PBUS_WRITE_4(8,PBUS_READ_4(8)&0x3FFF); 
  sc->pbusinten=0; 
  /* Envoie le signal � l'application. */
  if (sc->cproc!=NULL) psignal(sc->cproc,sc->csignal);
 } 
 else
 {
  if (status&0x40000000)
  {
   /* Frame Ok */
   BUFSYNC_POST;
   sc->buf_ok=1;
   sc->in_dma=0;
  } 
  else
  {
   /* Pointer slot avail */
  }
 }
 return 0;
}

#define PBUS_WAIT \
  tsleep(sc,PUSER | PCATCH,"pbusio",(HZ/10000)?(HZ/10000):1)
  
int
pbusioctl(dev, cmd, addr, flag, proc)
	dev_t dev;
	u_long cmd;
	int flag;
	caddr_t addr;
	struct proc *proc;
{
 struct pbus_softc *sc= pbus_cd.cd_devs[0];
 struct pbus_io *parm=(struct pbus_io *)addr;
 unsigned long *fsize=(unsigned long *)addr;
 /* PBUS IOctl */
 if (minor(dev)==1)	/* PBUS */
 {
  switch (cmd)
  {
   case PBUS_READ:
    PBUS_WRITE_4(8,(parm->addr<<8)|PBUS_RnW|sc->pbusinten);
    PBUS_WRITE_4(8,(parm->addr<<8)|PBUS_CLK|PBUS_RnW|sc->pbusinten);
    PBUS_WAIT;
    parm->data=PBUS_READ_4(8)&0xFF;
    PBUS_WRITE_4(8,(parm->addr<<8)|PBUS_RnW|sc->pbusinten);
    PBUS_WAIT;
    break;
   case PBUS_WRITE:
    PBUS_WRITE_4(8,(parm->addr<<8)|(parm->data)|sc->pbusinten);
    PBUS_WRITE_4(8,(parm->addr<<8)|PBUS_CLK|(parm->data)|sc->pbusinten);
    PBUS_WAIT;
    PBUS_WRITE_4(8,(parm->addr<<8)|(parm->data)|sc->pbusinten);
    PBUS_WAIT;
    PBUS_WRITE_4(8,(parm->addr<<8)|PBUS_RnW|sc->pbusinten);
    break;
   case PBUS_INTDISABLE:
    sc->pbusinten=0; 
    PBUS_WRITE_4(8,0|PBUS_RnW|sc->pbusinten);
    break; 
   case PBUS_INTENABLE:
    sc->pbusinten=PBUS_INTEN; 
    PBUS_WRITE_4(8,0|PBUS_RnW|sc->pbusinten);
    break; 
   case PBUS_INTREAD:
    parm->ints=(PBUS_READ_4(8)>>16)&0x1F;
    break; 
  }
 }

 if (minor(dev)==0)	/* CAM */
 {
  switch (cmd)
  {
   case CAM_SETFRAMESIZE:
    PBUS_WRITE_4(0x0,1);
    sc->framesize=*fsize;
    break;
  }
 }

 return 0;
}

paddr_t
pbusmmap(dev_t dev, off_t offset, int nprot)
{
 return ENXIO;
}