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. * Set up Tx Channel address field for use with PP Cmd Register. * Store address field in BH register. * Inputs: AH = Output port number (0..3). * AL = Data byte. * command = TXDATA0 | INT_EN; * Align port num with address field (b1...b3), * set address for TXDatax, Strobe=0
*/
command |= INT_EN;
/* Disable interrupts so that the process is not interrupted, then * write the address associated with the current Tx channel to the * PP Command Reg. Do not set the Strobe signal yet.
*/
do {
portman_write_command(pm, command);
/* While the address lines settle, write parallel output data to * PP Data Reg. This has no effect until Strobe signal is asserted.
*/
portman_write_data(pm, mididata);
/* If PCP channel's TxEmpty is set (TxEmpty is read through the PP * Status Register), then go write data. Else go back and wait.
*/
} while ((portman_read_status(pm) & TXEMPTY) != TXEMPTY);
/* TxEmpty is set. Maintain PC/P destination address and assert * Strobe through the PP Command Reg. This will Strobe data into * the PC/P transmitter and set the PC/P BUSY signal.
*/
portman_write_command(pm, command | STROBE);
/* Wait for strobe line to settle and echo back through hardware. * Once it has echoed back, assume that the address and data lines * have settled!
*/
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'll reenable ints while we're waiting.
*/
while ((portman_read_status(pm) & BUSY) == BUSY)
cpu_relax();
/* Data sent. */
}
/* * Read MIDI byte from port * Attempt to read input byte from specified hardware input port (0..). * Return -1 if no data
*/ staticint portman_read_midi(struct portman *pm, int port)
{ unsignedchar midi_data = 0; unsignedchar cmdout; /* Saved address+IE bit. */
/* 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. * If data is available, read it.
*/ 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. */
/* Wait for strobe echo. */ while ((portman_read_status(pm) & ESTB) == ESTB)
cpu_relax();
return (midi_data & 255); /* Shift back and return value. */
}
/* * Checks if any input data on the given channel is available * Checks RxAvail
*/ staticint portman_data_avail(struct portman *pm, int channel)
{ int command = INT_EN; switch (channel) { case 0:
command |= RXDATA0; break; case 1:
command |= RXDATA1; break;
} /* Write hardware (assumme STROBE=0) */
portman_write_command(pm, command); /* Check multiplexed RxAvail signal */ if ((portman_read_status(pm) & RXAVAIL) == RXAVAIL) return 1; /* Data available */
/* No Data available */ return 0;
}
/* * Flushes any input
*/ staticvoid portman_flush_input(struct portman *pm, unsignedchar port)
{ /* Local variable for counting things */ unsignedint i = 0; unsignedchar command = 0;
switch (port) { case 0:
command = RXDATA0; break; case 1:
command = RXDATA1; break; default:
dev_warn(pm->card->dev, "%s Won't flush port %i\n",
__func__, port); return;
}
/* 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 * low in case we happen to be addressing the Rx ports at this time.
*/ /* 1 */
parport_write_data(p, 0);
/* Check if Tx circuitry is functioning properly. If initialized * unit TxEmpty is false, send out char and see if it goes true.
*/ /* 8 */
parport_write_control(p, TXDATA0); /* Tx channel 0, strobe off. */
/* If PCP channel's TxEmpty is set (TxEmpty is read through the PP * Status Register), then go write data. Else go back and wait.
*/ /* 9 */ if ((parport_read_status(p) & TXEMPTY) == 0) return 2;
/* 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.