diff --git a/ppd/PPD.pm b/ppd/PPD.pm
index 00dc9e509093e0d91cac3c52fc5c6cacebbb5c9a..14206f45364ece359c83ca0d5c18f3d5ef603f35 100644
--- a/ppd/PPD.pm
+++ b/ppd/PPD.pm
@@ -29,13 +29,24 @@ our @EXPORT = qw(define_group define_ui_group switch_group declare get set maybe
 #	Priority => pri,	# OrderDependency priority, default = 100
 #	Values => [		# possible values (mandatory)
 #		{ Key => key,		# key (mandatory)
-#		  Name => key,		# descriptive name (default: same as Key)
+#		  Name => name,		# descriptive name (default: same as Key)
 #		  PS => string,		# PS code invocation to emit
 #		  String => string,	# Unquoted string to emit instead of PS code
 #		  Default => 1,		# if this is the default value
 #		},
 #	],
 #	Default => key,		# default value if not marked inside Values
+#	Custom => [		# further values with custom parameters (mostly a CUPS extension)
+#		PS => string,		# PS code invocation to emit (with parameters on the stack)
+#		Params => [		# list of parameters (mandatory)
+#			{ Key => key,		# key (mandatory)
+#			  Name => name,		# descriptive name (default: same as Key)
+#			  Unit => unit,		# unit: int / points / real / string / ...
+#			  Min => min,
+#			  Max => max,
+#			},
+#		]
+#	],
 # }
 my %keywords = ();
 
@@ -64,27 +75,27 @@ my $current_group_key;
 # ]
 my @constraints = ();
 
-sub define_group($$) {
-	my ($key, $g) = @_;
+sub define_group($) {
+	my ($g) = @_;
+	my $key = $g->{Key};
 	!defined $groups{$key} or die "Group $key already exists\n";
 	$groups{$key} = $g;
-	$g->{Key} = $key;
 	if ($g->{UI}) { push @ui_groups, $key; }
 	elsif ($g->{Head}) { push @head_groups, $key; }
 	else { push @nonui_groups, $key; }
 	$current_group_key = $key;
 }
 
-sub define_head_group($$) {
-	my ($key, $g) = @_;
+sub define_head_group($) {
+	my ($g) = @_;
 	$g->{Head} = 1;
-	define_group($key, $g);
+	define_group($g);
 }
 
-sub define_ui_group($$) {
-	my ($key, $g) = @_;
+sub define_ui_group($) {
+	my ($g) = @_;
 	$g->{UI} = 1;
-	define_group($key, $g);
+	define_group($g);
 }
 
 sub switch_group($) {
@@ -210,17 +221,17 @@ sub fonts($) {
 ### Known main keywords ###
 
 # Group "f": file description
-define_head_group('f', { Name => 'File version' });
+define_head_group({ Key => 'f', Name => 'File version' });
 declare('f',
 	[ 'FormatVersion',		'q!',	'4.3' ],
 	[ 'LanguageEncoding',		's!',	'ISOLatin1' ],
 	[ 'LanguageVersion',		's!',	'English' ],
-	[ 'FileVersion',		's!',	undef ],
+	[ 'FileVersion',		'q!',	undef ],
 	[ 'PCFileName',			's!',	undef ],
 );
 
 # Group "p": product description
-define_head_group('p', { Name => 'Product description' });
+define_head_group({ Key => 'p', Name => 'Product description' });
 declare('p',
 	[ 'Manufacturer',		'q!',	undef ],
 	[ 'ModelName',			'q!',	undef ],	# default: copy Product
@@ -231,7 +242,7 @@ declare('p',
 );
 
 # Group "d": device capabilities
-define_head_group('d', { Name => 'Device capabilities' });
+define_head_group({ Key => 'd', Name => 'Device capabilities' });
 declare('d',
 	[ 'ColorDevice',		'b',	0 ],
 	[ 'DefaultColorSpace',		's',	'Gray' ],
@@ -250,13 +261,13 @@ declare('d',
 );
 
 # Group "c": CUPS options
-define_head_group('c', { Name => 'CUPS options' });
+define_head_group({ Key => 'c', Name => 'CUPS options' });
 declare('c',
 	[ 'cupsProtocol',		's',	undef ],
 );
 
 # Group "j": JCL options
-define_head_group('j', { Name => 'JCL options' });
+define_head_group({ Key => 'j', Name => 'JCL options' });
 declare('j',
 	[ 'JCLBegin',			'q',	undef ],
 	[ 'JCLToPSInterpreter',		'q',	undef ],
@@ -264,7 +275,7 @@ declare('j',
 );
 
 # Group "fonts": Fonts
-define_group('fonts', { Name => 'Fonts' });
+define_group({ Key => 'fonts', Name => 'Fonts' });
 
 ### Formatting of PPD ###
 
@@ -299,7 +310,7 @@ sub heading($) {
 
 sub get_default($) {
 	my ($o) = @_;
-	$o->{Default} and return $o->{Default};
+	exists $o->{Default} and return $o->{Default};	# may be undef
 	for my $val (@{$o->{Values}}) {
 		return $val->{Key} if $val->{Default};
 	}
@@ -310,14 +321,21 @@ sub emit_option($) {
 	my ($o) = @_;
 	my $key = $o->{Key};
 	print "%* === $key ===\n";
+
 	my $jcl = ($o->{JCL} // ($key =~ /^JCL/)) ? "JCL" : "";
 	if (defined $o->{Choice}) {
 		print "*${jcl}OpenUI *$key/", ($o->{Name} // $o->{Key}), ": ", $o->{Choice}, "\n";
+	}
+
+	if (defined($o->{Choice}) || defined($o->{Priority}) || defined($o->{Section})) {
 		my $pri = $o->{Priority} // 100;
 		my $sec = $o->{Section} // ($jcl ? "JCLSetup" : "AnySetup");
 		print '*', ((defined $o->{Choice}) ? "" : 'NonUI'), "OrderDependency $pri $sec *$key\n";
 	}
-	print "*Default$key: ", get_default($o), "\n";
+
+	# Normal option
+	my $def = get_default($o);
+	print "*Default$key: $def\n" if defined $def;
 	for my $v (@{$o->{Values}}) {
 		my $ps = $v->{PS};
 		print "*$key ", $v->{Key};
@@ -332,7 +350,22 @@ sub emit_option($) {
 		}
 		print "\n";
 	}
+
 	if (defined $o->{Choice}) { print "*${jcl}CloseUI *$key\n"; }
+
+	my $c = $o->{Custom};
+	if ($c) {
+		print "\n";
+		print "*Custom$key True: ", format_value('i', $c->{PS}), "\n";
+		my $i = 0;
+		for my $p (@{$c->{Params}}) {
+			$i++;
+			print "*Param$key ", $p->{Key};
+			print '/', $p->{Name} if defined($p->{Name}) && $p->{Name} ne $p->{Key};
+			printf ": %d %s %d %d\n", $i, $p->{Unit}, $p->{Min}, $p->{Max};
+		}
+	}
+
 	print "\n";
 }
 
@@ -402,7 +435,7 @@ sub generate() {
 	fill_defaults();
 	check_missing();
 
-	print "*PPD-Adobe: ", get('FormatVersion'), "\n";
+	print "*PPD-Adobe: ", format_value('q', get('FormatVersion')), "\n";
 	print "*% PPD file generated by UCW PPD generator\n";
 
 	for my $g (@head_groups, @ui_groups, @nonui_groups) {
diff --git a/ppd/PPD/Paper.pm b/ppd/PPD/Paper.pm
index 921fe07882d913f78125af0150f80646c2cf98fb..7464b6a954b8ca0c828a43a1198a3dad6310bc23 100644
--- a/ppd/PPD/Paper.pm
+++ b/ppd/PPD/Paper.pm
@@ -68,7 +68,7 @@ sub add_papers($) {
 	}
 	$o->{DefPaper} //= 'A4';
 
-	define_ui_group('Media', { Name => 'Media settings' });
+	define_ui_group({ Key => 'Media', Name => 'Media settings' });
 
 	option({
 		Key => 'PageSize',
@@ -85,6 +85,16 @@ sub add_papers($) {
 			}
 		} sort keys %real_media ],
 		Default => $o->{DefPaper},
+		Custom => {
+			PS => 'pop pop pop << /PageSize [5 -2 roll] >> setpagedevice',
+			Params => [
+				{ Key => 'Width', Unit => 'points', Min => $minw, Max => $maxw },
+				{ Key => 'Height', Unit => 'points', Min => $minh, Max => $maxh },
+				{ Key => 'WidthOffset', Unit => 'points', Min => 0, Max => 0 },
+				{ Key => 'HeightOffset', Unit => 'points', Min => 0, Max => 0 },
+				{ Key => 'Orientation', Unit => 'int', Min => 1, Max => 1 },
+			]
+		},
 	});
 
 	option({
@@ -131,6 +141,18 @@ sub add_papers($) {
 		} sort keys %real_media ],
 		Default => $o->{DefPaper},
 	});
+
+	declare('Media',
+		[ 'LandscapeOrientation',	's',	'Plus90' ],
+		[ 'MaxMediaWidth',		'q',	$maxw ],
+		[ 'MaxMediaHeight',		'q',	$maxh ],
+		[ 'HWMargins',			's',	sprintf("%d %d %d %d", $margh, $margv, $margh, $margv) ],	# left, bottom, right, top
+	);
+
+	option({
+		Key => 'LeadingEdge',
+		Values => [{ Key => 'PreferLong', PS => "", Default => 1 }],
+	});
 }
 
 42;
diff --git a/ppd/gen-hp b/ppd/gen-hp
index 89a312400041d05a77bc0a22f70ea583d7fdc61c..e509a3ca6511afec29885c30f7a96631004c8c42 100755
--- a/ppd/gen-hp
+++ b/ppd/gen-hp
@@ -21,7 +21,7 @@ set('Protocols', 'PJL TBCP');
 
 set('cupsProtocol', 'None');
 
-define_ui_group('Basic', { Name => 'Basic options' });
+define_ui_group({ Key => 'Basic', Name => 'Basic options' });
 
 option({
 	Key => 'Duplex',
@@ -86,6 +86,17 @@ PPD::Paper::add_papers({
 	MarginH => 16, MarginV => 16,
 	PSPageSize => sub { my ($m) = @_; return sprintf("<< /PageSize [%d %d] >> setpagedevice", $m->{W}, $m->{H}); },
 });
+switch_group('Media');
+
+# Initialize media selection mechanism
+option({
+	Key => 'HPInit',
+	Priority => 0,
+	Section => 'DocumentSetup',
+	Values => [
+		{ Key => 'Init', PS => '<< /DeferredMediaSelection true /ImagingBbox null /MediaClass null >>' },
+	]
+});
 
 option({
 	Key => 'MediaType',
@@ -120,6 +131,13 @@ option({
 		{ Key => 'Tray2', Name => 'Tray 2', PS => '<< /ManualFeed false /MediaPosition 0 >> setpagedevice' },
 		{ Key => 'Tray3', Name => 'Tray 3', PS => '<< /ManualFeed false /MediaPosition 1 >> setpagedevice' },
 	],
+	Default => 'Tray2',
+});
+
+option({
+	Key => 'RequiresPageRegion',
+	Values => [{ Key => 'All', String => 'True' }],
+	Default => undef,
 });
 
 constrain(undef, 'InputSlot', 'MediaType', sub {
@@ -133,6 +151,18 @@ constrain(undef, 'Duplex', 'MediaType', sub {
 	return !($dp ne 'None' && $mt =~ /^(Labels|Transparency|Bond)$/);
 });
 
+option({
+	Key => 'HPPaperPolicy',
+	Name => 'Fit to Page',
+	Choice => 'PickOne',
+	Priority => 10,
+	Values => [
+		{ Key => 'PromptUser', Name => 'PromptUser', PS => '', Default => 1 },
+		{ Key => 'NearestSizeAdjust', Name => 'Nearest Size and Scale', PS => '<< /Policies << /DeferredMediaSelection true /PageSize 3 >> >> setpagedevice' },
+		{ Key => 'NearestSizeNoAdjust', Name => 'Nearest Size and Crop', PS => '<< /Policies << /DeferredMediaSelection true /PageSize 5 >> >> setpagedevice' },
+	],
+});
+
 # As reported by the printer
 # (versions set to "(1.0)", because the printer reports just "(.)")
 fonts( <<'AMEN' );
@@ -231,4 +261,6 @@ ZapfChancery-MediumItalic: Standard (1.0) Standard ROM
 ZapfDingbats: Special (1.0) Special ROM
 AMEN
 
+# FIXME: Omitted configuration of halftoning
+
 generate();