staticvoid portman_write_midi(struct portman *pm, int port, u8 mididata)
{ int command = ((port + 4) << 1);
/* Get entering data byte and port number in BL and BH respectively. *SetupTxChanneladdressfieldforusewithPPCmdRegister. *StoreaddressfieldinBHregister. *Inputs:AH=Outputportnumber(0..3). *AL=Databyte. *command=TXDATA0|INT_EN; *Alignportnumwithaddressfield(b1...b3), *setaddressforTXDatax,Strobe=0
*/
command |= INT_EN;
/* Disable interrupts so that the process is not interrupted, then *writetheaddressassociatedwiththecurrentTxchanneltothe *PPCommandReg.DonotsettheStrobesignalyet.
*/
do {
portman_write_command(pm, command);
/* While the address lines settle, write parallel output data to *PPDataReg.ThishasnoeffectuntilStrobesignalisasserted.
*/
portman_write_data(pm, mididata);
/* If PCP channel's TxEmpty is set (TxEmpty is read through the PP *StatusRegister),thengowritedata.Elsegobackandwait.
*/
} while ((portman_read_status(pm) & TXEMPTY) != TXEMPTY);
/* TxEmpty is set. Maintain PC/P destination address and assert *StrobethroughthePPCommandReg.ThiswillStrobedatainto *thePC/PtransmitterandsetthePC/PBUSYsignal.
*/
portman_write_command(pm, command | STROBE);
/* Wait for strobe line to settle and echo back through hardware. *Onceithasechoedback,assumethattheaddressanddatalines *havesettled!
*/
while ((portman_read_status(pm) & ESTB) == 0)
cpu_relax();
/* Release strobe and immediately re-allow interrupts. */
portman_write_command(pm, command);
while ((portman_read_status(pm) & ESTB) == ESTB)
cpu_relax();
/* PC/P BUSY is now set. We must wait until BUSY resets itself. *We'llreenableintswhilewe'rewaiting.
*/
while ((portman_read_status(pm) & BUSY) == BUSY)
cpu_relax();
/* Make sure clocking edge is down before starting... */
portman_write_data(pm, 0); /* Make sure edge is down. */
/* Set destination address to PCP. */
cmdout = (port << 1) | INT_EN; /* Address + IE + No Strobe. */
portman_write_command(pm, cmdout);
while ((portman_read_status(pm) & ESTB) == ESTB)
cpu_relax(); /* Wait for strobe echo. */
/* After the address lines settle, check multiplexed RxAvail signal. *Ifdataisavailable,readit.
*/ if ((portman_read_status(pm) & RXAVAIL) == 0) return -1; /* No data. */
/* Set the Strobe signal to enable the Rx clocking circuitry. */
portman_write_command(pm, cmdout | STROBE); /* Write address+IE+Strobe. */
while ((portman_read_status(pm) & ESTB) == 0)
cpu_relax(); /* Wait for strobe echo. */
/* The first data bit (msb) is already sitting on the input line. */
midi_data = (portman_read_status(pm) & 128);
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
/* Data bit 6. */
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
midi_data |= (portman_read_status(pm) >> 1) & 64;
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
/* Data bit 5. */
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
midi_data |= (portman_read_status(pm) >> 2) & 32;
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
/* Data bit 4. */
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
midi_data |= (portman_read_status(pm) >> 3) & 16;
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
/* Data bit 3. */
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
midi_data |= (portman_read_status(pm) >> 4) & 8;
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
/* Data bit 2. */
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
midi_data |= (portman_read_status(pm) >> 5) & 4;
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
/* Data bit 1. */
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
midi_data |= (portman_read_status(pm) >> 6) & 2;
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
/* Data bit 0. */
portman_write_data(pm, 0); /* Cause falling edge while data settles. */
midi_data |= (portman_read_status(pm) >> 7) & 1;
portman_write_data(pm, 1); /* Cause rising edge, which shifts data. */
portman_write_data(pm, 0); /* Return data clock low. */
/* Set address for specified channel in port and allow to settle. */
portman_write_command(pm, command);
/* Assert the Strobe and wait for echo back. */
portman_write_command(pm, command | STROBE);
/* Wait for ESTB */ while ((portman_read_status(pm) & ESTB) == 0)
cpu_relax();
/* Output clock cycles to the Rx circuitry. */
portman_write_data(pm, 0);
/* Flush 250 bits... */ for (i = 0; i < 250; i++) {
portman_write_data(pm, 1);
portman_write_data(pm, 0);
}
/* Deassert the Strobe signal of the port and wait for it to settle. */
portman_write_command(pm, command | INT_EN);
/* Wait for settling */ while ((portman_read_status(pm) & ESTB) == ESTB)
cpu_relax();
}
staticint portman_probe(struct parport *p)
{ /* Initialize the parallel port data register. Will set Rx clocks *lowincasewehappentobeaddressingtheRxportsatthistime.
*/ /* 1 */
parport_write_data(p, 0);
/* Initialize the parallel port command register, thus initializing *hardwarehandshakelinestomidibox: * *Strobe=0 *InterruptEnable=0
*/ /* 2 */
parport_write_control(p, 0);
/* Check if Portman PC/P 2x4 is out there. */ /* 3 */
parport_write_control(p, RXDATA0); /* Write Strobe=0 to command reg. */
/* Check for ESTB to be clear */ /* 4 */ if ((parport_read_status(p) & ESTB) == ESTB) return1; /* CODE 1 - Strobe Failure. */
/* Set for RXDATA0 where no damage will be done. */ /* 5 */
parport_write_control(p, RXDATA0 | STROBE); /* Write Strobe=1 to command reg. */
/* Check if Tx circuitry is functioning properly. If initialized *unitTxEmptyisfalse,sendoutcharandseeifitgoestrue.
*/ /* 8 */
parport_write_control(p, TXDATA0); /* Tx channel 0, strobe off. */
/* If PCP channel's TxEmpty is set (TxEmpty is read through the PP *StatusRegister),thengowritedata.Elsegobackandwait.
*/ /* 9 */ if ((parport_read_status(p) & TXEMPTY) == 0) return2;
/* While any input data is waiting */ while ((portman_read_status(pm) & INT_REQ) == INT_REQ) { /* If data available on channel 0,
read it and stuff it into the queue. */ if (portman_data_avail(pm, 0)) { /* Read Midi */
midivalue = portman_read_midi(pm, 0); /* put midi into queue... */ if (pm->mode[0] & PORTMAN2X4_MODE_INPUT_TRIGGERED)
snd_rawmidi_receive(pm->midi_input[0],
&midivalue, 1);
} /* If data available on channel 1,
read it and stuff it into the queue. */ if (portman_data_avail(pm, 1)) { /* Read Midi */
midivalue = portman_read_midi(pm, 1); /* put midi into queue... */ if (pm->mode[1] & PORTMAN2X4_MODE_INPUT_TRIGGERED)
snd_rawmidi_receive(pm->midi_input[1],
&midivalue, 1);
}
device = platform_device_alloc(PLATFORM_DRIVER, device_count); if (!device) return;
/* Temporary assignment to forward the parport */
platform_set_drvdata(device, p);
if (platform_device_add(device) < 0) {
platform_device_put(device); return;
}
/* Since we dont get the return value of probe
* We need to check if device probing succeeded or not */ if (!platform_get_drvdata(device)) {
platform_device_unregister(device); return;
}
/* register device in global table */
platform_devices[device_count] = device;
device_count++;
}
staticvoid snd_portman_detach(struct parport *p)
{ /* nothing to do here */
}
staticint snd_portman_dev_probe(struct pardevice *pardev)
{ if (strcmp(pardev->name, DRIVER_NAME)) return -ENODEV;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.